Calendar/Date timezone Conversion issue - java

I will get a Date like Sat May 31 16:38:17 GMT 2014. In DB also column has the same value. But when I will search for date like Sat May 31 16:30:00 GMT 2014 it wont search. But If I give less than 5:30 hours like Sat May 31 11:00:00 GMT 2014 . It works fine.
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone( "GMT-0:00" ));
cal.setTimeInMillis(inputDate.getTime());
cal.set(Calendar.MILLISECOND, 0);
inputDate = cal.getTime();

The underlying implementation of Date and Calendar both use the same system: a long representing milliseconds since 1st of January 1970, 0:00:00 GMT.
See Here for Date (lines 136 & 168) and HERE for Calendar (line 778)
So this gets us to this:
cal.setTimeInMillis(inputDate.getTime());
// this gets the long from the Date and puts it into the Calendar
// nothing is changed, you only get added functionality
// even if you change the Timezone this only affects how it is displayed
cal.set(Calendar.MILLISECOND, 0);
// the long is modified by setting the that represents only milliseconds to zero
inputDate = cal.getTime();
//the long is stored in a Date and returned
You get back a minimally altered Date object. Without the second instruction there would be no change at all.
This explains why nothing is converted, but not why the select doesn't work.
From the info you gave it seems there is a mismatch in the timezones of trinity of the DB, the JVM and your system.
Something in the line of this: your system is set to IST and your JVM somehow interprets your system time as GMT. To check this you could run System.out.println(new Date()). If it writes out the timezone as GTM but the numbers are the same as your systems clock (IST) then that is your problem.
You could also check:
do the time-stamps of an insert statement match with what arrives in the database
do the time-stamps of a database entry match the one you receive after a select

Related

LocalDate inconsistency

I am trying to produce a Date object (java.util.Date) from a LocalDate object (java.time.LocalDate) in which I have the following criteria:
Allow a parameter that can subtract a certain number of days from the Date object
Have the Date & Time be the date and time currently in UTC
Have the time at the beginning of the day i.e. 00:00:00
The Timezone stamp (i.e. CDT or UTC) is irrelevant as I remove that from the String
To meet this criteria, I have created a test program, however I am getting interesting results when I modify a certain property of the LocalDate. See code below:
public static void main (String args[]) {
Long processingDaysInPast = 0L;
LocalDate createdDate1 = LocalDate.now(Clock.systemUTC()).minusDays(processingDaysInPast);
LocalDate createdDate2 = LocalDate.now(Clock.systemUTC()).minusDays(processingDaysInPast);
System.out.println(createdDate1);
System.out.println(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC));
System.out.println(Date.from(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC)));
System.out.println((createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
System.out.println(Date.from(createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
}
Output:
2017-08-14
2017-08-14T00:00:00Z
Sun Aug 13 19:00:00 CDT 2017
2017-08-14
2017-08-14T05:00:00Z
Mon Aug 14 00:00:00 CDT 2017
When I add the value Date.from(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC)) I get the expected output of the date, with a 00:00:00 time field. However, if I do not add this parameter, such as: Date.from(createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()) I get the resulting day before , at 19:00:00 why is this?
My main goal from this is to be able to capture a Date object, with the current UTC Date, and the Time zeroed out (StartOfDay).
When you do:
createdDate2.atStartOfDay().atZone(ZoneId.systemDefault())
First, createdDate2.atStartOfDay() returns a LocalDateTime, which will be equivalent to 2017-08-14 at midnight. A LocalDateTime is not timezone-aware.
When you call atZone(ZoneId.systemDefault()), it creates a ZonedDateTime with the respective date (2017-08-14) and time (midnight) in the system's default timezone (ZoneId.systemDefault()). And in your case, the default timezone is not UTC (it's "CDT", so it's getting midnight at CDT - just do System.out.println(ZoneId.systemDefault()) to check what your default timezone is).
To get the date at midnight in UTC, you can replace the default zone (ZoneId.systemDefault()) with UTC (ZoneOffset.UTC):
Date.from(createdDate2.atStartOfDay().atZone(ZoneOffset.UTC).toInstant())
Or (a shorter version):
Date.from(createdDate2.atStartOfDay(ZoneOffset.UTC).toInstant())
Of course you can also do the same way you did with createdDate1:
Date.from(createdDate2.atStartOfDay().toInstant(ZoneOffset.UTC))
They're all equivalent and will result in midnight at UTC.
Just a quick note: short timezone names like CDT or PST are not real timezones.
The API uses IANA timezones names (always in the format Region/City, like America/Chicago or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CDT or PST) because they are ambiguous and not standard.
There are lots of different timezones that can use CDT as abbreviation. This happens because a timezone is the set of all different offsets that a region had, has and will have during history. Just because many places uses CDT today, it doesn't mean they all used in the past at the same periods, nor that it'll be used by all in the future. As the history differs, a timezone is created for each region.

Java Date object parsing precision is off on SimpleDateFormat

I have a date as a string 2016-10-07T12:46:23Z and after parsing to Date object using SimpleDateFormat is converted to Fri Oct 07 08:46:22 EDT 2016 which is 1 sec precision off. Debugging that code it came that it was parsed to Fri Oct 07 08:46:22.998 EDT 2016
SimpleDateFormat to parse as looks like
DATE_FORMAT_ISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
and the code to parse looks like
String dateStr = valuesArray.getString(0);
values[0] = RESTUtils.DATE_FORMAT_ISO8601.parse(dateStr);
Any tips how to get proper seconds value after parsing?
The expression new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC")) defines an offset not of zero, but 2 milliseconds, see Javadoc, thus explaining the observed result of "Fri Oct 07 08:46:22.998 EDT 2016".
The constant SimpleTimeZone.UTC is not intended to indicate an offset (as mandated as first argument to SimpleTimeZone-constructor). Its numerical value of "2" is rather a mode to denote how to interprete start or end time parameters for other constructors.
Therefore the correct solution to interprete the trailing "Z" in your input (ISO-8601-notation for zero offset) is:
DATE_FORMAT_ISO8601.setTimeZone(TimeZone.getTimeZone("GMT"));
Alternatively, if you really want to use the class SimpleTimeZone:
DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(0, "UTC"));
And if you are on Java-8, you could also do this:
Instant instant = Instant.parse("2016-10-07T12:46:23Z");
System.out.println(instant); // 2016-10-07T12:46:23Z
System.out.println(Date.from(instant)); // Fri Oct 07 14:46:23 CEST 2016
You are seeing the second difference when you add the time zone as UTC using SimpleTimeZone, if you comment that part out you will get the exact seconds.
String str = "2016-10-07T12:46:24Z";
SimpleDateFormat DATE_FORMAT_ISO8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
// DATE_FORMAT_ISO8601.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
System.out.println(DATE_FORMAT_ISO8601.parse(str));
SimpleTimeZone is not meant to be used to define the time zone. Per the documentation
SimpleTimeZone is a concrete subclass of TimeZone that represents a
time zone for use with a Gregorian calendar. The class holds an offset
from GMT, called raw offset, and start and end rules for a daylight
saving time schedule. Since it only holds single values for each, it
cannot handle historical changes in the offset from GMT and the
daylight saving schedule, except that the setStartYear method can
specify the year when the daylight saving time schedule starts in
effect.
The correct way to set the timezone is by doing the following
DATE_FORMAT_ISO8601.setTimeZone(TimeZone.getTimeZone("UTC"));

Can't convert time to GMT

My problem is that I want to convert the local time to GMT. I am able to convert the actual time and save it to Parse but the problem is that Parse applies its own:
Wed Feb 24 10:00:00 GMT+05:30 2016
This is the date that I am getting after converting to GMT00:00 but the problem is the GMT+05:30 that is actually false as my date is actually in GMT. Now when I put this date in the server it further decreases the time by 5:30 hrs. So how can we change this GMT+05:30 to GMT+00:00
If you are using java 8. you could utilize from the new time library.
As you tell it seems what you want, is to have a stamp in UTC which is GMT+00
more about time library here
This line:
System.out.println(Instant.now().toString());
gives
2016-02-25T17:54:55.420Z
Hope it makes thing more clear to you.
We'll start with the current local time.
Calendar cal = Calendar.getInstance(); // automatically produces and instance of the current date/time
As I understand it, your local date is accurate to GMT but your time is 5:30 ahead of actual GMT.
In order to subtract 5:30 from your local time you can perform the following.
cal.add(Calendar.HOUR, -5);
cal.add(Calendar.MINUTE, -30);
System.out.println(cal.getTime());
Conversely, if you would like to add to the time field, you can simply use:
cal.add(Calendar.HOUR, 5); // note I have removed the minus(-) symbol
cal.add(Calendar.MINUTE, 30); // note I have removed the minus(-) symbol
System.out.println(cal.getTime());

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

Java Calendar: 1am switchover to standard time (from DST)

I have some code that uses Calendar.set() to return the beginning of the hour for a given date value. I encountered the following issue on Sunday Nov 4th, 2012 (Eastern Timezone - EDT to EST switchover):
public void testStartOfHourDST1() {
Calendar cal = Calendar.getInstance();
long time = 1352005200000L; // Nov 4, 2012, 1AM EDT
cal.setTimeInMillis(time);
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
System.out.println(new Date(time));
System.out.println(new Date(cal.getTimeInMillis()));
System.out.println(System.getProperty("java.version"));
assertEquals(cal.getTimeInMillis(), time); // fails
return;
}
Ouput:
Sun Nov 04 01:00:00 EDT 2012
Sun Nov 04 01:00:00 EST 2012
1.6.0_35
Perhaps this is not the correct way to be using calendar, but running the same test for the next hour (or previous hour) works fine. Is this a JVM issue?
Thanks
It's not really an issue, in the sense that it is deterministic and doing what it was programmed to do. It's an issue if you would prefer that it pick the earlier of the two 1ams!
After changing fields on the Calendar the only information it has is "1am in US/Eastern". Well, your timezone had two 1ams that day, which one is it supposed to pick? The authors of OpenJDK made a decision that when presented with this ambiguity, they would always interpret it as the later one, in standard time. This comment is from java.util.GregorianCalendar OpenJDK 6:
// 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
// can be in standard or DST. Both are valid representations (the rep
// jumps from 1:59:59 DST to 1:00:00 Std).
// Again, we assume standard time.
If you print out the actual values of the numbers you will see cal.getTimeInMillis() has actually been changed by an hour from the value of time.
Getting the correct time zone is very important. For example, as I'm sure you are aware the system current time in milliseconds is measured from midnight on the 1st of January 1970. This is well documented. The Date constructor JavaDoc says:
public Date(long date)
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.
which is fine, but makes the output of this program a little hard to understand at first:
import java.util.Date;
import java.util.TimeZone;
import java.text.SimpleDateFormat;
public class Demo {
public static void main(String[] args) {
TimeZone tz = TimeZone.getTimeZone("Europe/London");
Date d = new Date(-3600000);
SimpleDateFormat df = new SimpleDateFormat("MMMM dd, yyyy HH:mm:ss.SSS z");
df.setTimeZone(tz);
System.out.println(String.format("%8dms -> %s",
Long.valueOf(d.getTime()) ,df.format(d)));
d.setTime(0);
System.out.println(String.format("%8dms -> %s",
Long.valueOf(d.getTime()) ,df.format(d)));
}
}
The output is:
-3600000ms -> January 01, 1970 00:00:00.000 GMT
0ms -> January 01, 1970 01:00:00.000 GMT
As you can see, the epoch is apparently displaced by an hour!
Except it is not. If you use the "GMT" time zone explicitly, all is well. The "Europe/London" time zone is simply tricky like that.
When working with Calendars, understand the time zone you are using or be caught out.

Categories

Resources