Android milliseconds with zone offset to Date - android

I current have (from server) a date stamp returned as ticks (.NET Date).
In general I managed to convert the above by subtracting by 10000 to produce secs and offset accordingly to get EPOC ms.
Now, the issue is that the ms passed from server include the zone offset and what I needed to do is get a TimeZone object for the zone (always the same) and subtract the ms offset (depending on DST) from the original value to produce a new object to properly get a Date.
Any better way of doing this without so many conversion?
private static long netEpocTicksConv = 621355968000000000L;
public static Date dateTimeLongToDate(long ticks) {
TimeZone greeceTz = TimeZone.getTimeZone("Europe/Athens");
Calendar cal0 = new GregorianCalendar(greeceTz);
long time = (ticks - netEpocTicksConv)/ 10000;
time -= greeceTz.getOffset(time);
cal0.setTimeInMillis(time);
Date res = cal0.getTime();
return res;
}

Here's some code which doesn't quite do the right thing near DST transitions:
private static final long DOTNET_TICKS_AT_UNIX_EPOCH = 621355968000000000L;
private static final TimeZone GREECE = TimeZone.getTimeZone("Europe/Athens");
public static Date dateTimeLongToDate(long ticks) {
long localMillis = (ticks - DOTNET_TICKS_AT_UNIX_EPOCH) / 10000L;
// Note: this does the wrong thing near DST transitions
long offset = GREECE.getOffset(localMillis - GREECE.getRawOffset());
long utcMillis = localMillis - offset;
return new Date(utcMillis);
}
There's no need to use a Calendar here.
You can get it to be accurate around DST transitions unless it's actually ambiguous, in which case you could make it either always return the earlier version or always return the later version. It's fiddly to do that, but it can be done.
By subtracting the offset for standard time, we're already reducing the amount of time during which it will be incorrect. Basically this code now says, "Subtract the standard time (no daylight savings) offset from the local time, to get an approximation to the UTC time. Now work out the offset at that UTC time."

Related

Calculate earlier and later times, then compare with a given time

I need to calculate if a certain time is between 30 minutes earlier and 20 minutes later than the current time.
Any idea how to do this?
The problem is when the time is 23:50h, for example. So I can't do a simple comparison since 23 is greater than 00. But I must consider it smaller since it's another day.
Example:
Now is 23:45. Testing 23:50.
23:45 - 30 minutes = 23:15.
23:45 + 20 minutes = 00:05.
Is 23:50 between 23:15 and 00:05?
Another example:
Now is 00:05. Testing 00:15.
00:05 - 30 minutes = 23:35.
00:05 + 20 minutes = 00:25.
Is 00:15 between 23:35 and 00:25?
--
minSdkVersion is 22, and this further limits the available solutions.
The easiest way to go is :
Compare Hours separately from minutes.
Or also you can take the Hours, multiply them for 60 and then add the returning value to the minutes amount, that will end up with a "only minute" calculation between the 2 times. You can make whatever operation you need.
The only case you should calculate is that one you are in a different day, but that dipends and what you are trying to accomplish!
CODE IN JAVA (OLD VERSION):
public class Main
{
public static void main(String[] args)
{
//Input TIME
String date = "23.45";
//Calculating the TIME in MINUTES ONLY
int date_m = normalizeTime(date);
//CALCULATE MAX AND MIN TIMES
int max = date_m+20;
int min = date_m-30;
/*
Working like that we don't
need to worry about the day Before or After
*/
//JUST DEBUG PRINTS TO SHOW YOU THAT
System.out.println("MAX TIME : "+max);
System.out.println("MIN TIME : "+min);
//The TIME that has to be tested
String testDate = "23.50";
//Calculating the TIME in MINUTES ONLY
int testDate_m = normalizeTime(testDate);
//JUST A DEBUG PRINT TO SHOW YOU THE TESTED TIME
System.out.println("TESTED TIME : "+testDate_m);
/*
If the testDate_m is Between the MAX and MIN values it's
TRUE else it's FALSE
If needed you can adjust with >= or <=
That doesn't matter for the logic.
*/
if(testDate_m<max && testDate_m>min)
System.out.println("IT IS BETWEEN!");
else
System.out.println("IT ISN'T BETWEEN!");
//DONE!
}
/*
Just a Method to clean up the code:
Basically it will Split the string in HOURS and MINUTES
and it will make a simple operation of : Hour*60(Transforming it to minutes) + minutes
The return is an INT that represent the inserted TIME as a MINUTE ONLY TIME.
If the returned number is more than 24*60 it's the Day Next (don't need to worry about that)
If the returned number is less than 0 it's the Previous Day (don't need to worry about that)
*/
private static int normalizeTime(String time)
{
int h = Integer.parseInt(time.substring(0,2));
int m = Integer.parseInt(time.substring(3,5));
return h*60+m;
}
}
CODE IN JAVA (NEW VERSION) :
public class Main
{
public static void main(String[] args)
{
boolean inTime = true;
//Input TIME
String date = "23.50";
//Calculating the TIME in MINUTES ONLY
int date_m = normalizeTime(date);
//CALCULATE MAX AND MIN TIMES
int max = date_m+20;
int min = date_m-30;
int prevMin = max;
int nextMax = min;
if(min<0)
{
prevMin = 24*60+min;
nextMax = 24*60+max;
}
else if(max>24*60)
{
prevMin = min-24*60;
nextMax = max-24*60;
}
/*
Working like that we don't
need to worry about the day Before or After
*/
//JUST DEBUG PRINTS TO SHOW YOU THAT
System.out.println("Between :"+min+" and "+max);
System.out.println("OR");
System.out.println("Between : "+prevMin+" and "+nextMax);
//The TIME that has to be tested
String testDate = "00.05";
//Calculating the TIME in MINUTES ONLY
int testDate_m = normalizeTime(testDate);
//JUST A DEBUG PRINT TO SHOW YOU THE TESTED TIME
System.out.println("TESTED TIME : "+testDate_m);
/*
If the testDate_m is Between the MAX and MIN values it's
TRUE else it's FALSE
If needed you can adjust with >= or <=
That doesn't matter for the logic.
*/
if((testDate_m<max && testDate_m>min) || (testDate_m<nextMax && testDate_m>prevMin))
System.out.println("IT IS BETWEEN!");
else
System.out.println("IT ISN'T BETWEEN!");
//DONE!
}
/*
Just a Method to clean up the code:
Basically it will Split the string in HOURS and MINUTES
and it will make a simple operation of : Hour*60(Transforming it to minutes) + minutes
The return is an INT that represent the inserted TIME as a MINUTE ONLY TIME.
If the returned number is more than 24*60 it's the Day Next (don't need to worry about that)
If the returned number is less than 0 it's the Previous Day (don't need to worry about that)
*/
private static int normalizeTime(String time)
{
int h = Integer.parseInt(time.substring(0,2));
int m = Integer.parseInt(time.substring(3,5));
return h*60+m;
}
}
The easiest way is just to work with timestamps.
long time = new Date().getTime();
long thiry_earlier = time - minutes_to_ms(30);
long twenty_later = time + minutes_to_ms(20);
if(compare < twenty_later && compare > thirty_earlier) {
//do whatever
}
long minutes_to_ms(long minutes) {
return minutes*60*1000;
}
There's some nicer conversion functions you can use nowdays I'm just too lazy to look them up. But working with raw timestamps makes everything easier for comparisons.

How to compare date and time in kotlin android?

I have an app on the PlayStore and I am building a feature where the user will not see ads more than a specific number in one day.
I am thinking about comparing the current date and time to the previously saved one but haven't find a proper way to do that.
How can I compare date and time to know if 24 hours have passed or not?
Some posts that I found but not helpful:
medium.com
stackoverflow
stackoverflow
tl;dr
[This Answer uses Java syntax. You’ll have to translate to Kotlin syntax.]
if
(
Duration // Represents elapsed time on the scale of hours-minutes-seconds.
.between( // Calculates elapsed time between two points in time.
Instant.parse( "2021-03-23T15:30:57.013678Z" ) , // Last moment when an ad was show.
Instant.now() // Current moment.
) // Returns a `Duration` object.
.toHours() // Extract total number of whole hours from the `Duration` object.
>= 24L // Test if equals-to or greater-than 24 hours.
)
{ show ad }
java.time
You asked:
… know if 24 hours have passed or not?
Use the modern java.time classes defined in JSR 310. The java.time classes are built into Android 26 and later. Most of the functionality is available in earlier Android using the latest tooling’s “API desugaring“.
Instant adShown = Instant.parse( "2021-03-23T15:30:57.013678Z" ) ;
Instant now = Instant.now() ;
Duration d = Duration.between( adShown , now ) ;
long hoursSinceAdShown = d.toHours() ;
if( hoursSinceAdShown >= 24L ) { … show ad }
Record your next ad-showing as text in standard ISO 8601 format.
String output = Instant.now().toString() ;
2021-03-23T15:30:57.013678Z
Your Question asked for two different things:
Once per day
Every 24 hours
The first involves a calendar, dates, and a time zone. The second does not. I showed you code for the second.
You can use a scheduled executor service to trigger from a background thread the next showing of an ad at a specific moment. Search Stack Overflow to learn more as this has been covered many times already.
Use this code to check the current date, Yesterday or Particulardate. Pass Epoch time to this method
// input format (we get a value as Epoch)
private val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
private val outputFormat = SimpleDateFormat("MMM dd")
// have to pass the time value as Epoch time.
private fun calculateDateMonth(time: String): String {
var returnValue = ""
val dateTime = DateTime((time.toLong()) * 1000L)
val inputTime = inputFormat.parse(dateTime.toString())
val convertDateMonth = outputFormat.format(inputTime!!)
val timeInMilliseconds = outputFormat.parse(convertDateMonth)!!
val mTime: Calendar = Calendar.getInstance()
mTime.setTimeInMillis(timeInMilliseconds.time)
val now = Calendar.getInstance()
returnValue = when {
now[Calendar.DATE] == mTime[Calendar.DATE] // check isToday
now[Calendar.DATE] - mTime[Calendar.DATE] == 1 // check Yesterday
else -> convertDateMonth // Month and Date
}
return returnValue
}

Different behavior of PeriodFormatter on different devices (JodaTime)

I'm implementing count down timer for the android app using JodaTime.
Depending of devices the output is different.
DateTime openingDateTime = new DateTime(2018, DateTimeConstants.JUNE, 14, 21, 0, 0, DateTimeZone.forID("Europe/Moscow"));
DateTime nowDateTime = DateTime.now(DateTimeZone.forID("Europe/Moscow"));
long difference = openingDateTime.getMillis() - nowDateTime.getMillis();
(...)
onTick(difference);
(...)
PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
.printZeroAlways()
.appendDays().appendSuffix(" day", " days")
.appendSeparator(" ")
.appendHours()
.appendSeparator(":")
.appendMinutes()
.appendSeparator(":")
.appendSeconds()
.toFormatter();
(...)
#Override
public void onTick(long millisUntilFinished) {
Duration duration = new Duration(millisUntilFinished);
Period period = duration.toPeriod(PeriodType.dayTime());
tvCounter.setText(periodFormatter.print(period));
}
On the one device output is correct: 491 days 4:39:18
on the other is wrong: 0 days 11788:49:11.
What am I doing wrong?
Thanks to your comments, I can now reproduce your problem. Just add following static initializer to your test class (at first place) to simulate the device where you observe your expected output:
static {
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
}
According to the spec (see also the accepted answer on this SO-post), the conversion duration.toPeriod(periodType) should only use so-called precise duration fields, that is hours, minutes, seconds and milliseconds but not days.
My analysis of source code of Joda-Time (v2.9.6):
The internal class org.joda.time.chrono.BasicChronology contains following constant:
private static final DurationField cDaysField = new PreciseDurationField(DurationFieldType.days(), 86400000L);
So we see that here this duration field is marked as "precise", but: The subclass ZonedChronology wraps it and override the behaviour of method isPrecise():
public boolean isPrecise() {
return iTimeField ? iField.isPrecise() : iField.isPrecise() && this.iZone.isFixed();
}
This shows an extra zone dependency of the precision property of the days()-duration-field, namely precise for fixed zones like UTC and else imprecise.
I don't know if the analyzed and observed behaviour is a feature or a bug. Let's say, it is dangerous to expect the creation of Period-objects by duration.toPeriod(...) to be zone-independent. And it is not documented there to have a precise days-component if the system zone is fixed.
Unfortunately, the implicit dependency on the default time zone is deeply coded into Joda-Time via its chronology-design. As workaround, you can use:
Period p = new Period(nowDateTime, openingDateTime, PeriodType.dayTime());

Android CPU usage of each function

Currently in my Android code what I am doing to calculate each function CPU Usage is -
double start = System.currentTimeMillis();
double start1 = Debug.threadCpuTimeNanos();
foo();
double end = System.currentTimeMillis();
double end1 = Debug.threadCpuTimeNanos();
double t = (end - start);
double t1 = (end1 - start1)/1000000;
double CPUusage;
if(t==0){
CPUusage = 0;
}else{
CPUusage = (t1/t) * 100;
}
I am doing t1/t to calculate CPU Usage. Is this a correct way of calculating CPU usage of each function in my Android code or is it conceptually wrong? Request someone to guide me in this.
From documentation:
static long currentTimeMillis()
Returns the current time in milliseconds since January 1, 1970 00:00:00.0 UTC.
Please, replace the double(s) you are using, with long(s).
While long(s) have precision issues, they are almost irrelevant for the variables used, also, the rounding will likely be close enough, that the returned value can be used in relation with each other
Also, you are comparing two independent values. Try either the current thread, or the full thread time.
From the Debug documentation:
public static long threadCpuTimeNanos()
Added in API level 1
Get an indication of thread CPU usage. The value returned indicates the amount of time that the current thread has spent executing code or waiting for certain types of I/O. The time is expressed in nanoseconds, and is only meaningful when compared to the result from an earlier call. Note that nanosecond resolution does not imply nanosecond accuracy. On system which don't support this operation, the call returns -1.
Try using, in the same Runnable (sequentially placed method calls):
long start = Debug.threadCpuTimeNanos();
foo();
long finish = Debug.threadCpuTimeNanos();
long outputValue = finish - start ;
System.out.println("foo() took " + outputValue + " ns.");

check current time between time interval android

I want to create an app that will allow the user to check whether or not the current time falls between a specified time interval. More specifically, I created a sql table using sqllite program, with the table specifying an end time and a start time for each record. The problem is that the type of data each field can be is limited to text, number, and other type other than a datetime type. So, how would I be able to check if the current time is between the start and end time since the format of time is in h:mm and not just an integer value that I could just do less than or greater than? Do I have to convert the current time to minutes?
You should be able to do the comparison even if time is not stored in the datetime type, here is a link that explains the conversion from string to time.
If that doesn't work, convert the time to seconds (int) and calculate the difference.
Try this. You can save and retrieve your time as String:
String to long: String.valueOf()
long to String: Long.valueOf()
Then, you use this procedure to check time:
//Time checker
private boolean timeCheck(long startTimeInput, long endTimeInput) {
long currentTime = System.currentTimeMillis();
if ((currentTime > startTimeInput) && (currentTime < endTimeInput)) {
return true;
} else {
return false;
}
}
And in your main program check it like this:
//You kept the times as String
if (timeCheck(Long.valueOf(start), Long.valueOf(end))) {
//it is in the interval
} else {
//not in the interval
}
I hope it helps.

Categories

Resources