Strange thing. I have SQLite Android database with dates kept as long values. I read them as Date objects ex.:
new Date (cursor.getLong(4))
Next when displaying I convert Date objects to String with toString() method. However sometimes the displayed String contains CET and sometimes CEST.
Sure the fact that time zone info is added is not surprising. What is surprising the fact that at the same device, with values get from database in the same time, being long values thus not containing any zone time information, java sometimes add CET and sometimes CEST. Why there is such a difference?
The only difference is that long value which gives in result CEST has time equal to 00:00:00 while those giving in result CET has time different.
Any idea?
The values themselves are totally time-zone agnostic, but your device is not. Your device has two time zones, CET and CEST, as part of its locale. Dates that fall during the time when daylight savings time was/is/will be active are given in CEST, other dates are reported as CET.
If you set your device to a locale that doesn't observe daylight savings time, only that one time zone will be reported.
To see why this makes sense, consider if you asked me what time it is now, and I said "13:35 CEST." Inasmuch as CEST is UTC+2, I'm correct, but you'd likely be confused. Because CEST isn't used at this time of year, it only makes sense to gives times in CET. That's why the timezone varies depending on the date.
Related
I am testing my app in different timezones. I manually changed my physical phone's timezone to be London UK which is GMT+00:00
However, when I print the timezone using myCalendar.getTimeZone().getDisplayName(true, TimeZone.SHORT), it prints:
GMT+01:00
Why's it adding an hour to the offset?
EDIT:
By setting the getDisplayName's first parameter to false, I get the correct GMT+00:00 but I am not sure why I should be setting it to false. As far as I know, London UK is always GMT+00:00? Am I wrong?
As far as I know, London UK is always GMT+00:00? Am I wrong?
Yes, you are wrong. The United Kingdom observes Greenwich Mean Time (GMT) in the winter, and observes daylight saving time, locally called "British Summer Time" (BST), in the summer.
GMT = UTC+00:00
BST = UTC+01:00
Reference here, and here.
According to the API, getDisplayName()'s first parameter indicates if daylight savings should be used.
Returns a name in the specified style of this TimeZone suitable for
presentation to the user in the default locale. If the specified
daylight is true, a Daylight Saving Time name is returned (even if
this TimeZone doesn't observe Daylight Saving Time). Otherwise, a
Standard Time name is returned.
This is probably why the time is an hour ahead with that value set to true, as a value of true will cause a daylight savings hour even if it isn't observed in that timezone.
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.
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
Can we get from which timezone the Long Value is produced?
I have long values of Date. I want to know from which timezone it is generated.
For e.g
Long value: 1435640400000
Date: 30 June 2015 CDT
I want to develop program which input will be the Date in long value
that will return output as Timezone with the respective
long value for 30 June 2015 12:00 AM GMT/UTC
The unix time (as it is called) is not a date. You can calculate a date from it but it really is just the duration of seconds (or ms) since 01/01/1970 at 00:00 UTC.
This means it has no timezone attached to it. You need the "target" timezone to calculate the actual date from it, but simply having this number does not include any timezone information (which means you'll need to get it somewhere else in order to calculate dates).
Think of the unix timestamp more as a duration than a date. It's like saying "I'll meet you in 30 minutes". Those 30 minutes do not have a timezone attached to them. To you and the person you're talking to, that meeting might happen at different dates (e.g. 2:30pm vs. 3:30pm) because of timezones. But it will still happen at the same point in time relative to the moment you said it.
I hope this makes the difference somewhat clearer.
There was a way to do this directly via the getTimezoneOffset() function in the Date class but that has been deprecated.
It has been replaced by
(Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)
I am using simple date format to allow users to specify which time zone they are sending data in:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,z");
This works fine:
e.g.
df.parse("2009-05-16 11:07:41,GMT");
However, if someone is always sending time in London time (i.e. taking into account daylight savings), what would be the approriate time zone String to add?
e.g. this doesnt work:
df.parse("2009-05-16 11:07:41,Western European Time");
System.out.println(date);
Sat May 16 12:07:41 BST 2009
I want to match the time to british time taking into daylight savings.
Thanks.
In daylight saving time, it's BST. In the rest of the year it's GMT.
I suggest that you use the generic name (for the whole year), which is Europe/London. You can use something like this:
String userInput = "2009-05-16 11:07:41,Europe/London";
String[] tokens = userInput.split(",");
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone(tokens[1]));
System.out.println(df.parse(tokens[0]));
The output in this case is:
Sat May 16 11:07:41 GMT+01:00 2009
So what exactly is your question - what ID for the TimeZone you should use? The following will print a list of all the available time zone identifiers:
for (String id : TimeZone.getAvailableIDs()) {
System.out.println(id);
}
I don't think it's possible to do exactly what you want to do using SimpleDateFormat on its own. TimeZone.parse(String) only accepts time zones, not time zone IDs, for example:
Time Zone ID Time Zone (Winter) Time Zone (Summer)
-------------------------------------------------------------
Europe/London GMT BST
If parse(...) accepted Europe/London there would be one hour in spring that would not be a valid Europe/London time and one hour in autumn that would map to two UTC times.
I think that the best you can do is follow Bruno Rothgiesser's suggestion, however you could accept the time zone ID as a separate user input, or do an additional string processing step to separate the time zone id from the user input string, and use it to work out whether the user probably means GMT or BST. The user's Locale might be a better way of working out what he/she means - although there are some assumptions involved in that idea.
The "what the user probably means" algorithm has to deal with two special cases - you can use TimeZone.inDaylightTime(Date) with userTime +/- 1 hour to work out if you might have one of these.