Transformation date to single time zone [duplicate] - java

This question already has answers here:
Convert timestamp in milliseconds to string formatted time in Java
(10 answers)
Closed 4 years ago.
I have two timestamps as milliseconds, which were created in different time zones and cannot convert to the same time zone.
Date_1 = 1525694035615 - Mon May 07 2018 11:53:55
Date_2 = 1525686835730 - Mon May 07 2018 09:53:55
Does any body know how to identify time zone and get values in UTC+0?
When I transform these timestamps always get values that these timestamps have timezone +0.

If your milliseconds timestamps created in Java they are always milliseconds from
midnight, January 1, 1970 UTC
And have nothing about time zone.
what you see:
Mon May 07 2018 11:53:55
Mon May 07 2018 09:53:55
Just string representations of those moments in time in the current JVM/Computer Time Zone
If you need to have a String representation in UTC time zone there are number of classes to do that. In all JDK there are Calendar implementations (e.g. GregorianCalendar). From Java 8 there is new API inspired by Joda time.
It should work better with timezones handling.

If you are getting timezone+0 that is because that is the default timezone given any fixed time in any amount (milliseconds in your example). You must tell it what timezone you are in if you want a different one that UTC+0.

Does any body know how to … get values in UTC+0?
I’m taking the easy part first:
OffsetDateTime dateTime = Instant.ofEpochMilli(1_525_694_035_615L)
.atOffset(ZoneOffset.UTC);
System.out.println(dateTime);
This prints:
2018-05-07T11:53:55.615Z
This agrees with what you said in the question. The Z in the end means UTC.
…how to identify time zone…
We can’t exactly. If you know the time to which the timestamp corresponds in the timezone where it was produced, we can calculate the offset. Since this is rather boring when the answer is UTC, I am taking a different example:
long timestamp = 1_525_708_128_067L;
LocalDateTime dateTimeInUnknownTimezone = LocalDateTime.of(2018, Month.MAY, 7, 18, 48, 48);
LocalDateTime utcDateTime = Instant.ofEpochMilli(timestamp)
.atOffset(ZoneOffset.UTC)
.toLocalDateTime()
.truncatedTo(ChronoUnit.SECONDS);
int offsetInSeconds = (int) ChronoUnit.SECONDS.between(utcDateTime, dateTimeInUnknownTimezone);
ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetInSeconds);
System.out.println(offset);
+03:00
Since the date-time has precision of seconds only, I am also truncating the UTC time to seconds to get the offset precise. From the offset of +03:00 we cannot unambiguously determine a time zone, though, since many time zones use this offset.

Related

Converting a string pattern of format 1/1/2010 3:23:12 PM +00:00 to a Java.util.Date

I am trying to convert a String with format 1/1/2010 3:23:12 PM +00:00 to a Java.util.Date
Unable to convert the String format to a Java Date.
It is not identifying the time asAM/PM
String s = "1/1/2010 3:23:12 PM +00:00";
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss a",Locale.ENGLISH);
Date date = sdf.parse(s));
Need the date converted with time identified as AM/PM
OffsetDateTime is what you're looking for.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy h:mm:ss a XXX");
OffsetDateTime time = OffsetDateTime.parse(str, formatter);
System.out.println(time);
Your pattern has some problems:
Your day-of-the-month is without a leading zero, yet you are using dd;
Same for month with MM;
Same for hour with HH;
You are using AM/PM in conjunction with a 24-hour hour format specifier (H); you should use h instead.
I don't know exactly how SimpleDateFormat handles the timezone part of the string, but no formatting specifiers for the timezone are given.
That's one of the reasons why I like this Date and Time API: it's pretty straightforward.
Ideone example
Unable to convert the String format to a Java Date. It is not
identifying the time as AM/PM
You are asking the impossible. A Date is a point in time (internally implemented as a count of milliseconds since the so-called epoch), so it “knows” nothing about AM and PM in your time zone.
That’s just the same, though, because the Date class was always poorly designed and is fortunately long outdated. You should not use it at all.
java.time
java.time, the modern Java date and time API that we should use instead of Date, comes closer to fulfilling your requirement. MC Emperor has already shown the basic code you need for parsing your datetime string. The output from his code is:
2010-01-01T15:23:12Z
There’s no AM or PM here. When we print an OffsetDateTime in this way, its toString method is implicitly called. It produces an ISO 8601 formatted string. ISO 8601 prescribes a 24 hour clock (no AM or PM). But! With assistance from the correct TemporalField object the OffsetDateTime is able to calculate and return whether it is in AM or PM. time.get(ChronoField.AMPM_OF_DAY) returns 0 for AM or 1 for PM:
System.out.println("AM or PM? 0 for AM. 1 for PM. time: "
+ time.get(ChronoField.AMPM_OF_DAY));
AM or PM? 0 for AM. 1 for PM. time: 1
So in this case we got 1 for PM as expected since your original string had PM in it.
I have deliberately not answered all of your question because much of it has been covered in other Stack Overflow questions and their answers already. So it’s better to keep the information there. I include links to a couple of relevant questions below.
What went wrong in your code?
There are at least two bugs in your code that each cause you to get an incorrect result. I tried running your code in America/Los_Angeles time zone and got
Fri Jan 01 03:23:12 PST 2010
The time printed is on a 24 hour clock (Date always does that), so we got 03:23:12 AM instead of PM. And we got the time in the default time zone (PST is for Pacific Standard Time), so the point in time corresponds to 11:23:12 AM at offset +00:00, the offset in the string.
The wrong clock hour comes from conflicting indications in your code: HH in the format pattern string is for hour of day from 00 through 23, so 3 is taken to mean 03 AM and apparently “wins” over the PM marker (for hour within AM or PM, from 1 through 12, you would have needed lowercase h).
The default time zone comes from the fact that you are making no attempt to parse the offset from the string (in conjunction with SimpleDateFormat being satisfied with not parsing all of the string).
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601
Question: want current date and time in “dd/MM/yyyy HH:mm:ss.SS” format
Question: Unable to parse DateTime-string with AM/PM marker
Question: Display current time in 12 hour format with AM/PM
Question: Convert String to java.util.Date

Local timezone date object to UTC timezone date object [duplicate]

This question already has answers here:
Calendar returns date in wrong time zone
(5 answers)
Closed 3 years ago.
I am trying to convert my datetime that is in local timezone into UTC date time.
Date localDate; // this is local date
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ") ;
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String dateStr = simpleDateFormat.format(localDate);
i am getting proper converted UTC time in dateStr now i want to convert it into Date object with UTC timezone only
but the moment i do that i am again getting the localDate.
//converting string to date object
simpleDateFormat.parse(dateStr)
does anyone know how can i convert local date object to UTC date object
here is the value i am getting while debugging
here dateStr is showing proper date in UTC but utcDate object is showing the local time
Date class is intended to reflect coordinated universal time (UTC) time. It can be formatted into ANY form you want, e.g. you can format it into your local time zone or UTC time zone.
See from javadoc: https://docs.oracle.com/javase/8/docs/api/java/util/Date.html
Although the Date class is intended to reflect coordinated universal time (UTC), it may not do so exactly, depending on the host environment of the Java Virtual Machine. Nearly all modern operating systems assume that 1 day = 24 × 60 × 60 = 86400 seconds in all cases. In UTC, however, about once every year or two there is an extra second, called a "leap second." The leap second is always added as the last second of the day, and always on December 31 or June 30. For example, the last minute of the year 1995 was 61 seconds long, thanks to an added leap second. Most computer clocks are not accurate enough to be able to reflect the leap-second distinction.

joda time to Date inconsistent time zones

I have a load of dates that I'd like to store in a database running on a server using BST:
2015-09-23
2024-05-07
2024-03-13
However they are stored in the DB as:
2015-09-23 01:00:00
2024-05-07 01:00:00
2024-03-13 00:00:00 <-- I need this to be 01:00:00
The values are converted to Date prior to being stored in the DB. I noticed the following when debugging:
TimeZone timeZone = Calendar.getInstance().getTimeZone();
System.out.println(timeZone.getDisplayName(false, TimeZone.SHORT));
System.out.println(new SimpleDateFormat("zzz").format(new Date()));
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd").withZone(DateTimeZone.UTC);
System.out.println(formatter.parseDateTime("2015-09-23").toDate());
System.out.println(formatter.parseDateTime("2024-05-07").toDate());
System.out.println(formatter.parseDateTime("2024-03-13").toDate());
The first two dates are using BST and the last one is GMT. Is is possible to make them all use the same time zone?
GMT
BST
Wed Sep 23 01:00:00 BST 2015
Tue May 07 01:00:00 BST 2024
Wed Mar 13 00:00:00 GMT 2024
First of all, keep in mind that java.util.Date doesn't have a timezone (more details about it can be read here).
What happens is that Date.toString() method uses the system's default timezone to print its value (check the value of TimeZone.getDefault() in your JVM, it'll probably be Europe/London).
And in Europe/London timezone, the offset is equals to UTC in the winter (which is printed as GMT) and is +01:00 in the summer (which is printed as BST, aka British Summer Time). These different 3-letter names denotes the offset change, but it doesn't mean the dates "changed" their timezone.
Also consider that timezone is not only the offset or the name, but the set of all offset changes that occur in a region during history (when the changes occur, and the offsets before and after each change).
So, the dates doesn't have different timezones, because:
In the same timezone there can be more than 1 offset. And some changes in the offset cause the change in the 3-letter name - although the use of these 3-letter names is widely used, they're ambiguous and not standard.
java.util.Date doesn't have a timezone, so it can't change it.
If you want to save these objects in a DB, what you should care about is the timestamp (the number of milliseconds from 1970-01-01T00:00:00Z), which is preserved when converting to Date.
If you check the timestamp millis in the objects created, you'll see that it wasn't changed:
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd").withZone(DateTimeZone.UTC);
DateTime d1 = formatter.parseDateTime("2015-09-23");
DateTime d2 = formatter.parseDateTime("2024-05-07");
DateTime d3 = formatter.parseDateTime("2024-03-13");
// comparing timestamp millis between DateTime and java.util.Date
System.out.println(d1.getMillis() == d1.toDate().getTime());
System.out.println(d2.getMillis() == d2.toDate().getTime());
System.out.println(d3.getMillis() == d3.toDate().getTime());
All 3 cases above prints true, meaning that they represent the same instant in time (so the dates hasn't changed).
Actually, you can see that all DateTime objects were in UTC:
System.out.println(d1);
System.out.println(d2);
System.out.println(d3);
This prints:
2015-09-23T00:00:00.000Z
2024-05-07T00:00:00.000Z
2024-03-13T00:00:00.000Z
Conclusion:
you can save the Date objects without any problem, as their values are correct
if you want to display the dates to the user, you can use the DateTime objects (and use a DateTimeFormatter if you want a different format), because they don't use the default TimeZone in the toString() method.
Try this:
SimpleTimeZone UTCTimeZone = new SimpleTimeZone(0, "UTC");
TimeZone.setDefault(UTCTimeZone);
All the date object will use UTC as default timezone for you backend code

DateTime to date conversion, not the correct value

I try to convert a string into a datetime:
String dateString = "2015-01-14T00:00:00-04:00";
DateTimeFormatter df = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ");
DateTime dt = df.parseDateTime(dateString);
If I display dt.toDate()
I get: Tue Jan 13 23:00:00 EST 2015
So there is a time problem.
Without the DateTimeFormatter, I get the same issue.
It's getting the correct value - basically 4am UTC, which is midnight in a UTC offset of -04:00 (as per the original text), or 11pm on the previous day for EST (as per the displayed result).
The problem is that you're using java.util.Date.toString(), which always returns the date in the system time zone. Note that a java.util.Date only represents an instant in time - it has no notion of a time zone itself, so its toString() method just uses the system default.
If you want to retain the time zone information (or in this case, the offset from UTC information - you don't have a full time zone) then stick to DateTime instead of converting to Date. Ideally, avoid java.util.Date/java.util.Calendar entirely. Stick to Joda Time and/or java.time.*.

Joda-Time, Daylight Saving Time change and date time parsing

I have the following problem using Joda-Time for parsing and producing date and time around Daylight Saving Time (DST) hours. Here is an example (please, note that March 30th 2008 is Daylight Saving change in Italy):
DateTimeFormatter dtf = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss");
DateTime x = dtf.parseDateTime("30/03/2008 03:00:00");
int h = x.getHourOfDay();
System.out.println(h);
System.out.println(x.toString("dd/MM/yyyy HH:mm:ss"));
DateTime y = x.toDateMidnight().toDateTime().plusHours(h);
System.out.println(y.getHourOfDay());
System.out.println(y.toString("dd/MM/yyyy HH:mm:ss"));
I get the following output:
3
30/03/2008 03:00:00
4
30/03/2008 04:00:00
When i parse hour I get hour is 3. In my data structure I save the day storing midnight time, and then I have some value for each hour of the day (0-23). Then, when I write out the date, I re-compute the full date time making midnight plus hour. When I sum 3 hours to my midnight I get 04:00:00! And if I parse it again, I get hour 4!
Where is my mistake? Is there some way to get hour 2 when I parse or get hour three when I print out?
I have also tried to build output by hand:
String.format("%s %02d:00:00", date.toString("dd/MM/yyyy"), h);
but in this case for hour 2, I produce 30/03/2008 02:00:00 which is not a valid date (since hour 2 does not exist) and cannot be parsed any more.
Thank you in advance for your help.
Filippo
When I sum 3 hours to my midnight I get 04:00:00! And if I parse it again, I get hour 4! Where is my mistake?
You mentioned already that this date is exactly when the time changes. So there is no mistake. March 30, 2010 00:00 CEST (the timezone in Italy) is precisely speaking March 29, 2010 23:00 UTC. When you add 3 hours, you will get March 30, 2010 02:00 UTC. But this is post the moment, that we switch times (which happens on 01:00 UTC), so when you convert time to local timezone you get March 30, 04:00. That's correct behavior.
Is there some way to get hour 2 when I parse or get hour three when I print out?
No, because March 30, 2010 02:00 CEST does not exist. Precisely at March 30, 2010 01:00 UTC we switch time from +1 hour to +2 hours versus UTC, so March 30, 2010 00:59 UTC is March 30, 2010: 01:59 CEST, but March 30, 2010 01:00 UTC become March 30, 2010 03:00 CEST. No 02:xx hour exist on that particular date.
BTW. In a week you can expect another "fun". Can you tell what date in UTC this refers to:
October 31, 2010 02:15 CEST ?
Well, the funny part is, we do not know. It could be either 0ctober 31, 2010 00:15 UTC (before actual time switch) or October 31, 2010 01:15 UTC (after the switch).
That's exactly why you should always store date and times in relation to UTC and convert them to local time zone before displaying, otherwise you risk an ambiguity.
HTH.
The data structure you are saving your data is not very optimal for the days with daylight saving time. Your day in this particular day should only have 23 hours.
If you do:
DateTimeFormatter dtf = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss").withLocale(Locale.US);
DateTime x = dtf.parseDateTime("30/03/2008 00:00:00");
DateTimeFormatter parser = DateTimeFormat.fullDateTime();
System.out.println("Start:"+parser.print(x));
DateTime y = x.plusHours(4);
System.out.println("After add of 4:"+parser.print(y));
You get the expected result, that the time is 05:00.
I recommend that you change the way you store your day and use a date. If not, you must handle daylight saving time when storing the hour of day.
You might do something like this:
In the case where we move the time forward one hour, as this case, you must store 4 and not 5 as the time for 5. And when you calculate the time, you should use the plusHours() method to get the actual time. I think you might get away with something like:
public class DateTest {
private static final int HOUR_TO_TEST = 2;
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss");
DateTime startOfDay = dtf.parseDateTime("30/03/2008 00:00:00");
/* Obtained from new DateTime() in code in practice */
DateTime actualTimeWhenStoring = startOfDay.plusHours(HOUR_TO_TEST);
int hourOfDay = actualTimeWhenStoring.getHourOfDay();
int hourOffset = startOfDay.plusHours(hourOfDay).getHourOfDay();
System.out.println("Hour of day:" + hourOfDay);
System.out.println("Offset hour:" + hourOffset);
int timeToSave = hourOfDay;
if (hourOffset != hourOfDay) {
timeToSave = (hourOfDay + (hourOfDay - hourOffset));
}
System.out.println("Time to save:" + timeToSave);
/* When obtaining from db: */
DateTime recalculatedTime = startOfDay.plusHours(timeToSave);
System.out.println("Hour of time 'read' from db:" + recalculatedTime.getHourOfDay());
}
}
...or basicly something like that. I'd write a test for it if you choose for going down this route. You can change the HOUR_TO_TEST to see that it moves passed the daylight saving time.
Building on the correct answers by Paweł Dyda & Knubo…
ISO 8601 For String Format
You should never store (serialize) a date-time as a string in the format you mentioned: "30/03/2008 03:00:00". Problems:
Omitted time zone.
Day, Month, Year order is ambiguous.
Should have been translated to UTC time.
If you must serialize a date-time value to text, use a reliable format. The obvious choice is the ISO 8601 standard format. Even better is converting the local time to UTC (Zulu) time zone and then out to ISO 8601 format. Like this: 2013-11-01T04:48:53.044Z
No Midnight
The midnight methods in Joda-Time are deprecated in favor of the Joda-Time method withTimeAtStartOfDay() (see doc). Some days do not have a midnight.
Example Code in Joda-Time 2.3
Some comments about this source code:
// © 2013 Basil Bourque. This source code may be used freely forevery by anyone taking full responsibility for doing so.
// Joda-Time - The popular alternative to Sun/Oracle's notoriously bad date, time, and calendar classes bundled with Java 7 and earlier.
// http://www.joda.org/joda-time/
// Joda-Time will become outmoded by the JSR 310 Date and Time API introduced in Java 8.
// JSR 310 was inspired by Joda-Time but is not directly based on it.
// http://jcp.org/en/jsr/detail?id=310
// By default, Joda-Time produces strings in the standard ISO 8601 format.
// https://en.wikipedia.org/wiki/ISO_8601
Example showing 23 hours in the day of DST (Daylight Saving Time) in Rome Italy, while the day after has 24 hours. Note that the time zone (for Rome) is specified.
// Time Zone list: http://joda-time.sourceforge.net/timezones.html
org.joda.time.DateTimeZone romeTimeZone = org.joda.time.DateTimeZone.forID("Europe/Rome");
org.joda.time.DateTime dayOfDstChange = new org.joda.time.DateTime( 2008, 3, 30, 0, 0, romeTimeZone ) ; // Day when DST
org.joda.time.DateTime dayAfter = dayOfDstChange.plusDays(1);
// How many hours in this day? Should be 23 rather than 24 on day of Daylight Saving Time "springing ahead" to lose one hour.
org.joda.time.Hours hoursObjectForDay = org.joda.time.Hours.hoursBetween(dayOfDstChange.withTimeAtStartOfDay(), dayAfter.withTimeAtStartOfDay());
System.out.println( "Expect 23 hours, got: " + hoursObjectForDay.getHours() ); // Extract an int from object.
// What time is 3 hours after midnight on day of DST change?
org.joda.time.DateTime threeHoursAfterMidnightOnDayOfDst = dayOfDstChange.withTimeAtStartOfDay().plusHours(3);
System.out.println( "Expect 4 AM (04:00) for threeHoursAfterMidnightOnDayOfDst: " + threeHoursAfterMidnightOnDayOfDst );
// What time is 3 hours after midnight on day _after_ DST change?
org.joda.time.DateTime threeHoursAfterMidnightOnDayAfterDst = dayAfter.withTimeAtStartOfDay().plusHours(3);
System.out.println( "Expect 3 AM (03:00) for threeHoursAfterMidnightOnDayAfterDst: " + threeHoursAfterMidnightOnDayAfterDst );
Example of storing a date-time by first translating to UTC. Then upon restoring the date-time object, adjust to the desired time zone.
// Serialize DateTime object to text.
org.joda.time.DateTimeZone romeTimeZone = org.joda.time.DateTimeZone.forID("Europe/Rome");
org.joda.time.DateTime dayOfDstChangeAtThreeHoursAfterMidnight = new org.joda.time.DateTime( 2008, 3, 30, 0, 0, romeTimeZone ).withTimeAtStartOfDay().plusHours(3);
System.out.println("dayOfDstChangeAtThreeHoursAfterMidnight: " + dayOfDstChangeAtThreeHoursAfterMidnight);
// Usually best to first change to UTC (Zulu) time when serializing.
String dateTimeSerialized = dayOfDstChangeAtThreeHoursAfterMidnight.toDateTime( org.joda.time.DateTimeZone.UTC ).toString();
System.out.println( "dateTimeBeingSerialized: " + dateTimeSerialized );
// Restore
org.joda.time.DateTime restoredDateTime = org.joda.time.DateTime.parse( dateTimeSerialized );
System.out.println( "restoredDateTime: " + restoredDateTime );
// Adjust to Rome Italy time zone.
org.joda.time.DateTime restoredDateTimeAdjustedToRomeItaly = restoredDateTime.toDateTime(romeTimeZone);
System.out.println( "restoredDateTimeAdjustedToRomeItaly: " + restoredDateTimeAdjustedToRomeItaly );
When run:
dayOfDstChangeAtThreeHoursAfterMidnight: 2008-03-30T04:00:00.000+02:00
dateTimeBeingSerialized: 2008-03-30T02:00:00.000Z
restoredDateTime: 2008-03-30T02:00:00.000Z
restoredDateTimeAdjustedToRomeItaly: 2008-03-30T04:00:00.000+02:00

Categories

Resources