When I print date that I get from server, it shows Mon Jun 24 16:15:31 GMT+09:00 2019
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val date: Date? = formatter.parse(checkedDate) // date from server
val transformedDate = ("${String.format("%02d", date!!.month + 1)}.${String.format("%02d", date!!.date)}.${date.year + 1900}")
val title: String? = ("$transformedDate")
val longGmtTime = date.time
val mZone = TimeZone.getDefault()
val offset = mZone.getOffset(longGmtTime)
val longLocalTime = longGmtTime + offset - (9 * HOUR)
val localDate = Date() // local date
localDate.time = longLocalTime
val localFormatTime = formatter.format(localDate)
val transformedLocalDate = ("${String.format("%02d", localDate!!.month + 1)}.${String.format("%02d", localDate!!.date)}.${localDate.year + 1900}")
And it gives me server time: 2019-06-24 16:15:31 -> 06.24.2019, local time(Asia/Seoul)-> 2019-06-25 01:15:30 ->06.25.2019 for the result.
The server time and local time must be the same. But the local time shows somewhere else.
What's the problem?
What's the problem?
The gross problem list includes:
You are using the poorly designed and long outdated Java date and time classes Date, TimeZone and SimpleDateFormat.
You are using the deprecated methods getMonth, getDate and getYear of the Date class. These methods work unreliably across time zone, which is the main reason why they were deprecated.
You are doing the time zone conversion manually using addition, subtraction and multiplication. Date and time math is error-prone, and you should always leave it to proven library methods.
The millisecond count you get from Date.getTime is since the epoch of 1970-01-01T00:00:00 UTC. This is a unique moment in time and independent of time zone, so adding to and subtracting from the millisecond count for time zone conversion makes no sense.
I can reproduce your result when I set my JVM’s default time zone to Asia/Seoul and assume that HOUR is 0 (or some value in the range from 0 through 111). I assume that you had wanted HOUR to denote the number of milliseconds in an hour, 3 600 000 (at least usually, exceptions exist).
You were formatting your date by concatenating the results of calls to Strirg.format. It’s better to leave formatting to a specialized date formatter.
The fix: java.time
ZoneId serverTimeZone = ZoneId.of("Asia/Seoul");
DateTimeFormatter serverFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
ZoneId clientTimeZone = ZoneId.systemDefault();
String checkedDate = "2019-06-24 16:15:31";
ZonedDateTime serverDateTime = LocalDateTime.parse(checkedDate, serverFormatter)
.atZone(serverTimeZone);
ZonedDateTime clientDateTime = serverDateTime.withZoneSameInstant(clientTimeZone);
System.out.println("clientDateTime: " + clientDateTime);
Sorry that I can write and run only Java code, I trust you to translate. With my JVM’s time zone still set to Asia/Seoul I get:
clientDateTime: 2019-06-24T16:15:31+09:00[Asia/Seoul]
The server time and the client time are the same, as you requested. If instead I keep my own time zone, I get:
clientDateTime: 2019-06-24T09:15:31+02:00[Europe/Copenhagen]
So there is a conversion taking place.
To format the date:
DateTimeFormatter displayFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
.withLocale(Locale.forLanguageTag("ko-KR"));
String transformedLocalDate = clientDateTime.format(displayFormatter);
System.out.println("transformedLocalDate: " + transformedLocalDate);
transformedLocalDate: 2019. 6. 24.
Or if you insist on month.date.year:
DateTimeFormatter displayFormatter = DateTimeFormatter.ofPattern("MM.dd.u");
transformedLocalDate: 06.24.2019
A further recommendation would be to have your server deliver a date-time string in UTC in ISO 8601 format. That would go like 2019-06-24T07:15:31Z for the moment used in the examples.
Question: Can I use java.time with minSdk API level 23 on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601
You should specify setup server timezone instead of you device (which is default)
Related
I'm stuck with the daylight problem in android the time should be +3 GMT/UTC
but I'm getting only +2. is there any solution or I can't handle it? please find below my code
TimeZone.getDefault().useDaylightTime();
SimpleDateFormat df = new SimpleDateFormat("HH:mm",Locale.ENGLISH); //"2021-02-18T11:00:00"
df.setTimeZone(TimeZone.getTimeZone("UTC"));
return df.format(calendar.getTime());
Note that the DST OFFSET is returning zero. what should I do to handle daylight?
Another note my time is Jordan / Amman,
In winter this should return +2 but in summer it should return +3
java.time
Consider using java.time, the modern Java date and time API, for your date and time work. Let’s first declare a formatter for your desired time format:
private static final DateTimeFormatter TIME_FORMATTER
= DateTimeFormatter.ofPattern("HH:mm", Locale.ENGLISH);
Now you may format the time from your Calendar in this way:
// Assume you are getting a Calendar from somewhere
Calendar calendar = new GregorianCalendar();
ZonedDateTime dateTime = calendar.toInstant().atZone(ZoneId.systemDefault());
String dateTimeString = dateTime.format(TIME_FORMATTER);
System.out.println(dateTimeString);
I ran the code just now, that is, 16:33 in UTC or 19:33 in Jordan. The output was:
19:33
If you don’t depend on getting on old-fashioned Calendar from somewhere, it’s probably even simpler and cleaner. For example, to get the current time in your time zone:
String timeString
= LocalTime.now(ZoneId.systemDefault()).format(TIME_FORMATTER);
System.out.println(timeString);
What went wrong in your code?
You set the time zone of your SimpleDateFormat to UTC. So the time in UTC was printed regardless of your default time zone. And since UTC hasn’t got summer time (DST), no such was taken into account.
BTW, this method call of yours does nothing:
TimeZone.getDefault().useDaylightTime();
From the documentation:
Returns:
true if this TimeZone uses Daylight Saving Time, false,
otherwise.
So the method does not alter anything and certainly not the UTC time zone. It only queries whether the mentioned time zone uses summer time (daylight saving time). So since the Asia/Amman time zone does, it should return true in your case.
Question: Doesn’t java.time require Android API level 26?
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
Java 8+ APIs available through desugaring
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
I found that this gives a wrong date. but how i can not solve it. please someone help me.
I am new in android Development.
Thanks in advance;
String timestamp = "1538970640";
SimpleDateFormat formatter = new SimpleDateFormat("dd MMM 'at' hh:mm a z" );
String dateString = formatter.format(new Date(Long.parseLong(timestamp)));
This returns:
19 Jan at 01:29 AM GMT+06:oo
But it should be:
8 Oct at 9:50 AM GMT+06:00
The java.util.Date constructor accepts milliseconds since the Epoch, not seconds:
Allocates a Date object and initializes it to represent the specified number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.
The following code which uses ms is working:
String timestamp = "1538970640000"; // use ms NOT s
SimpleDateFormat formatter = new SimpleDateFormat("dd MMM 'at' hh:mm a z" );
String dateString = formatter.format(new Date(Long.parseLong(timestamp)));
08 Oct at 05:50 AM CEST
Demo
Part of the problem you were facing is that your date format omitted the year component, which was actually coming up as 1970.
java.time and ThreeTenABP
I recommend you use java.time, the modern Java date and time API, for your date and time work.
DateTimeFormatter timestampFormatter = new DateTimeFormatterBuilder()
.appendValue(ChronoField.INSTANT_SECONDS)
.toFormatter();
DateTimeFormatter targetFormatter
= DateTimeFormatter.ofPattern("d MMM 'at' h:mm a z", Locale.ENGLISH);
String timestamp = "1538970640";
ZonedDateTime dateTime = timestampFormatter.parse(timestamp, Instant.FROM)
.atZone(ZoneId.systemDefault());
String dateString = dateTime.format(targetFormatter);
System.out.println(dateString);
Output is (when time zone is set to GMT+06:00, which by the way is not a true time zone):
8 Oct at 9:50 AM GMT+06:00
I am not very happy about converting date and time from one string format to another, though. In your app you should not handle date and time as strings but as proper date and time objects, for example Instant or ZonedDateTime. When you get a string from somewhere (a server?), parse it into a date-time object first thing. Only when you need to give string output, for example to the user, format your date and time into a string in the user’s time zone.
That said, java.time performs your conversion with just two formatters. No need to parse into a low-level long first.
Two more points:
Give your output formatter a locale to control the language used. Since AM and PM are hardly used in other languages than English, I figured that Locale.ENGLISH might be appropriate. You decide.
Since you want 8 Oct at 9:50 AM GMT+06:00, use just one d for day of month and one h for clock hour. Two digits will still be printed if the numbers go over 9, for example 10 Oct at 11:50 AM GMT+06:00.
What went wrong in your code?
Your number, 1538970640 (10 digits), denotes seconds since the epoch. This is the classical definition of a Unix timestamp. The Date constructor that you used expects milliseconds since the epoch. This is typical for the outdated Java date and time classes and methods. These years milliseconds since the epoch are typically 13 digits. As you can see, the modern Java date and time classes have better support for seconds here.
Question: Doesn’t java.time require Android API level 26?
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in. In this case, instead of the constant Instant.FROM use the method references Instant::from.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
I've the date in format: YYYY-MM-DD
Output format required is:
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
And I want to get the date in ISO format as Start time of the day(starts from 12:00AM) and end time of the day(ends on 11:59PM) in America/Chicago timezone.
For eg. For the date: 2020-06-08 (June 8) the converted final output is like:
Start time of the day as Date: 2020-06-08T05:00:00.000Z
End time of the day as Date: 2020-06-09T04:59:59.999Z
Please help me here if anybody has any clue for the same.
Answer: http://m.uploadedit.com/bltc/1591511729781.txt
java.time and ThreeTenABP
I suggest using java.time, the modern Java date and time API, for such date and time math.
ZoneId zone = ZoneId.of("America/Chicago");
String dateString = "2020-06-08";
LocalDate date = LocalDate.parse(dateString);
Instant startOfDay = date.atStartOfDay(zone).toInstant();
Instant endOfDay = date.plusDays(1).atStartOfDay(zone).toInstant();
System.out.println("The day is from " + startOfDay + " (inclusive) to " + endOfDay + " (exclusive)");
Output is:
The day is from 2020-06-08T05:00:00Z (inclusive) to
2020-06-09T05:00:00Z (exclusive)
In order not to exclude the last millisecond of the day we need to count the day as lasting up to the first moment of the next day exclusive. If you do insist on subtracting a millisecond or just a nanosecond, it’s up to you to do so, of course. For example:
Instant endOfDay = date.plusDays(1).atStartOfDay(zone).minusNanos(1).toInstant();
The day is from 2020-06-08T05:00:00Z (inclusive) to
2020-06-09T04:59:59.999999999Z (inclusive and 1 nano more)
Edit: How to get milliseconds printed in the output? You most probably don’t need that. The format you are asking for is ISO 8601 (see the link at the bottom), the international standard. In ISO 8601 the fraction of second is optional, and leaving it out implies 0. So any API requiring ISO 8601 should accept the above. Only if not, the correct solution is to use a formatter. In this case we need to convert the time to UTC explicitly:
ZoneId zone = ZoneId.of("America/Chicago");
DateTimeFormatter formatterWithMillis = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
String dateString = "2020-06-08";
LocalDate date = LocalDate.parse(dateString);
OffsetDateTime startOfDay = date.atStartOfDay(zone)
.toOffsetDateTime()
.withOffsetSameInstant(ZoneOffset.UTC);
OffsetDateTime endOfDay = date.plusDays(1)
.atStartOfDay(zone)
.toOffsetDateTime()
.withOffsetSameInstant(ZoneOffset.UTC);
String startString = startOfDay.format(formatterWithMillis);
String endString = endOfDay.format(formatterWithMillis);
System.out.println("The day is from " + startString + " (inclusive) to " + endString + " (exclusive)");
The day is from 2020-06-08T05:00:00.000Z (inclusive) to
2020-06-09T05:00:00.000Z (exclusive)
Or after subtracting a nanosecond from the end time as before:
OffsetDateTime endOfDay = date.plusDays(1)
.atStartOfDay(zone)
.minusNanos(1)
.toOffsetDateTime()
.withOffsetSameInstant(ZoneOffset.UTC);
The day is from 2020-06-08T05:00:00.000Z (inclusive) to
2020-06-09T04:59:59.999Z (inclusive and 1 nano more)
(Since the time is truncated to whole milliseconds the 1 nano more doesn’t really make sense, but I don’t think that’s the point here.)
Question: Doesn’t java.time require Android API level 26?
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
But don't we have any other option apart from switching to ThreeTenBP
Library?
If you insisted, I suppose that a way through using Calendar, Date and SimpleDateFormat could be found. Those classes are poorly designed and long outdated, so with what I know and don’t know I would prefer ThreeTenABP.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601
Updated:
ZoneId zoneId = ZoneId.of("America/Chicago");
LocalDate localDate = LocalDate.parse("2020-06-08");
DateTimeFormatter newPattern = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZone(zoneId);
Instant startOfDay = localDate.atStartOfDay(zoneId).toInstant();
Instant endOfDay = LocalDateTime.of(localDate, LocalTime.MAX).atZone(zoneId).toInstant().truncatedTo(ChronoUnit.MILLIS);
System.out.println(startOfDay);
System.out.println(endOfDay);
With what I have gone through, the fraction 000 will not come in this but yes one can be sure that if there are no fraction of milliseconds then it is 000. I was not able to figure out how to bring this while formatting.
In case you find something then please add else, you can do it this by converting startDate to String and then appending the 000 to it.
Results
2020-06-08T05:00:00Z
2020-06-09T04:59:59.999Z
Im using SimpleDateFormat to get the current date and hour, the Date is working well but for unknown reasons the hour value is 3 hours backwards.
for example if I will run the code on 19:40 the time value will be 16:40 and I don't know why.
Would really appreciate some help.
String timeStamp = new SimpleDateFormat("M/d/yyyy&HH:mm").format(Calendar.getInstance().getTime());
java.time and ThreeTenABP
java.time, the modern Java date and time API, gives a pretty natural way to control the time zone. For example:
ZoneId zone = ZoneId.of("Asia/Istanbul");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/uuuu&HH:mm");
String timeStamp = ZonedDateTime.now(zone).format(formatter );
System.out.println(timeStamp);
When I ran this snippet just now, the output was:
6/6/2019&19:53
I don’t know what your time zone is and trust you to specify the correct one. It matters.
Question: Can I use java.time on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
What went wrong in your code?
As others have said, your issue is a time zone issue. Apparently your SimpleDateFormat had its time zone set to UTC. When you’re not specifying time zone, it picks up its time zone from the JVM, which in turn usually picks it up from the operating system if not specified otherwise. That your JVM is using UTC is a standard practice, so not that much of a surprise.
Anyway, the datetime classes you were using, SimpleDateFormat and Calendar, are poorly designed, the former in particular notoriously troublesome. Fortunately both are long outdated. Instead use java.time, the modern Java date and time API.
I've just noticed that the phone hour is 3 hours backwards as well. Is
there a way to change it?
Most likely the phone system clock is correct (maybe even updated automatically from a time server), but its time zone is set to UTC. There should be a way to set it to your time zone in the phone settings (then it will likely also be used by your JVM).
ISO 8601
As an aside your timestamp format is peculiar. I recommend that you use a standard format, best ISO 8601, and also that you include offset in the string so that even if the time zone was wrong, the time would still be unambiguous and correct. Two examples. First you may use UTC consciously:
String timeStamp = Instant.now().toString();
2019-06-06T16:57:19.493599Z
The trailing Z means UTC.
If you want your own time zone:
String timeStamp = OffsetDateTime.now(zone).toString();
2019-06-06T19:58:29.788376+03:00
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601
A Date does not have any timezone information; it's just a wrapper around a long that is assumed to be UTC epoch milliseconds. It's no coincidence that your timezone is 3 hours ahead of UTC and the formatted time is 3 hours out.
Although you can specify the timezone that SimpleDateFormat renders a Date in:
SimpleDateFormat format = new SimpleDateFormat("M/d/yyyy&HH:mm");
format.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
Due to their many problems, Date and Calendar are largely deprecated.
Use LocalDateTime and DateTimeFormatter instead:
String timeStamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("M/d/yyyy&HH:mm"));
I want to find difference between 2 timestamps. What I am doing is storing 1st timestamp in shared prefs
and try to subtractt it from the new timestamp. To get timestamp, I am using -
public static String setTimestamp() {
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
return dateFormat.format(new Date());
} catch (Exception e) {
return null;
}
}
How do I subtract 2 timestamps and check if the difference is smaller than 120 seconds?
You can find difference like this
long diffInMs = firstTimestamp - secondTimestamp;
long diffInSec = TimeUnit.MILLISECONDS.toSeconds(diffInMs);
Now you have got difference in seconds so just go ahead and check your condition
if(diffInSec < 120){
}
I suggest the following for getting a string for saving into your shared preferences:
String timestampToSave = Instant.now().toString();
Now to count the seconds since the time given in that string:
String timestampFromSharedPreferences = mySharedPrefs.getString(KEY, null);
long diffInSeconds = Duration.between(Instant.parse(timestampFromSharedPreferences),
Instant.now())
.getSeconds();
if (diffInSeconds < 120) {
System.out.println("Less than 120");
}
An Instant is an unambiguous point in time independent of time zone. Its string representation goes like 2018-04-16T09:26:27.929Z (ISO 8601). The Z in the end means UTC. So the above works even in the off case where the user changes the time zone setting of the device, or some other part of your program changes the time zone setting of your JVM. You notice that we do not need an explicit formatter for formatting the string and parsing it back into an Instant.
In case you want to compare to 2 minutes rather than 120 seconds, use toMinutes() instead of getSeconds().
In case you cannot change the string saved in shared preferences, you will need to cross you fingers that the time zone setting hasn’t been changed and then parse the string like this:
DateTimeFormatter timestampFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
Instant storedTimestamp = LocalDateTime.parse(timestampFromSharedPreferences, timestampFormatter)
.atZone(ZoneId.systemDefault())
.toInstant();
Now let Duration calculate the difference between the Instant objects as before.
I am using and recommending java.time, the modern Java date and time API. The SimpleDateFormat class that you were using is long outdated along with Date and is also notoriously troublesome. The modern API is so much nicer to work with.
Question: Can I use java.time on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26, I’m told) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.timeto Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601