Java Date, render with specific daylight mode - java

I have a Java Date that is from this summer during daylight savings time. For example:
Jun 01, 2009 06:00 AM PDT
My question is, how do I display this date as my local time zone and current daylight savings mode (in my case Pacific Standard Time)?
Jun 01, 2009 05:00 AM PST
Java's Date.toString() and SimpleDateFormat displays the date in the original daylight savings mode. Example:
System.out.println(new Date(1243861200000L));
outputs:
Mon Jun 01 06:00:00 PDT 2009
DateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy hh:mm aa zzz");
dateFormat.setTimeZone(TimeZone.getTimeZone("PST"));
System.out.println(dateFormat.format(new Date(1243861200000L)));
outputs:
Jun 01, 2009 06:00 AM PDT
What I really want to see is 5:00 AM PST (which is equivalent to 6:00 AM PDT). Is there a way to force it to use another daylight savings mode?
Follow up: By the way, this is the Windows XP behavior. A file created on June 1, 6 AM will be seen (by Explorer, Command Prompt, etc) as June 1, 5 AM during the winter.

I don't think there's a way to force the DateFormat to apply a TimeZone format to a time that couldn't exist. PST is only applicable in the Winter months and PDT is only used in the summer.
I formatted this date with all of the TimeZones returned by TimeZone.getAvailableIDs(), and found two that returned me PST for that particular time: Pacific/Pitcairn and SystemV/PST8. You could try using one of those, but I have no idea what other rules apply to either of those timezone objects.
If you're just concerned with getting the time with that offset, you could use GMT-8 as your TimeZone. However, that string will show up in your formatted date string instead of PST.
UPDATE: Here's a way to take any timezone and have it ignore all daylight savings time rules. You can grab a TimeZone object then grab another TimeZone.getTimeZone() object. On the second object set the Id and rawOffset to the corresponding object from the first TimeZone.
For example:
DateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy hh:mm aa zzz");
TimeZone defaultTimeZone = TimeZone.getDefault();
TimeZone timeZone = TimeZone.getTimeZone("");
timeZone.setID(defaultTimeZone.getID());
timeZone.setRawOffset(defaultTimeZone.getRawOffset());
dateFormat.setTimeZone(timeZone);
System.out.println(dateFormat.format(new Date(1243861200000L)));
This will print out exactly what you're looking for.

PST/PDT change throughout the year. Java attempts to determine which one is in affect on a given date. This things obviously change as the laws and regions change. Can you use an absolute time zone? Specifying the offset in GMT will be the same year around.
DateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy hh:mm aa zzz");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT-07:00"));
System.out.println(dateFormat.format(new Date(1243861200000L)));
Jun 01, 2009 06:00 AM GMT-07:00

this might do the trick:
/*
* Create a date that represents 1,243,861,200,000 milliseconds since
* Jan 1, 1970
*/
Date date = new Date(1243861200000L);
/*
* Print out the date using the current system's default format and time
* zone. In other words, this will print differently if you set the
* operating zone's time zone differently.
*/
System.out.println(date);
/*
* Specify the format and timezone to use
*/
DateFormat dateFormat = new SimpleDateFormat(
"MMM dd, yyyy hh:mm aa zzz");
TimeZone pstTZ = TimeZone.getTimeZone("PST");
dateFormat.setTimeZone(pstTZ);
System.out.println(dateFormat.format(date));
/*
* It looks like what you want is to actually display a different date
* (different # milliseconds since epoch) in the summer months. To do that, you
* need to change the date by subtracting an hour.
*/
if(pstTZ.inDaylightTime(date)){
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.HOUR, -1);
date = cal.getTime();
}
//now this should always print "5:00". However, it will show as 5:00 PDT in summer and 5:00 PST in the winter which are actually 2 different dates. So, I think you might need to think about exactly what it is you're trying to achieve.
System.out.println(dateFormat.format(date));

DateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy hh:mm aa zzz");
dateFormat.setTimeZone(TimeZone.getTimeZone("Pacific/Pitcairn"));
System.out.println(dateFormat.format(new Date(1243861200000L)));
Additional comments: zzz will print out PST, while z will print out GMT-08:00. TimeZone.getTimeZone("EST") works for for Eastern Standard Time, making me think this is a bug with TimeZone.getTimeZone("PST").
I suggest using predefined time zones, since they can be confusing:
public static final TimeZone ZONE_GREENWICH_MEAN_TIME = TimeZone.getTimeZone("GMT");
public static final TimeZone ZONE_EASTERN_DAYLIGHT_TIME = TimeZone.getTimeZone("America/New_York"); // EDT, GMT-04:00
public static final TimeZone ZONE_EASTERN_STANDARD_TIME = TimeZone.getTimeZone("EST"); // GMT-05:00
public static final TimeZone ZONE_PACIFIC_DAYLIGHT_TIME = TimeZone.getTimeZone("America/Los_Angeles"); // PDT, GTM-0700
public static final TimeZone ZONE_PACIFIC_STANDARD_TIME = TimeZone.getTimeZone("Pacific/Pitcairn"); // PST, GMT-08:00
I came across another time with a similar problem "2009-11-01 08:44:44". I tried iterating over all IDs and none would print EDT. The funny thing was that "2010-11-01 08:44:44" would print EDT. Between 1990 and 2010, only 2007, 2008 and 2010 would print EDT. When I checked the years from 0 to 2499, only 431 had EDT, with the first in 1940 (this must be when EDT was introduced). So of the 560 years (1940-2499), only 431 have an ID that prints EDT. From 1940 to 2006, there are only 10 years which have IDs which print EDT. After 2006, every 4, 5 or 10 years, there is a year which will not print EDT.

Related

Confused with Converting the date with SimpleDateFormat [duplicate]

This question already has answers here:
How to convert "Mon Jun 18 00:00:00 IST 2012" to 18/06/2012?
(5 answers)
Closed 5 years ago.
I have a problem with date converting. I use the following program and I expect the output: 19.05.2017
But the output is: 05.00.2017
Can anybody help?
String t = "Fri May 19 00:00:00 CEST 2017";
Date d = new SimpleDateFormat("EEE MMM DD hh:mm:ss zzzz YYYY", Locale.US).parse(t);
String s = new SimpleDateFormat("dd.mm.yyyy").format(d).toString();
System.out.println(s);
A surprising result. The oldfashioned classes SimpleDateFormat and friends are full of surprises. This is meant as a negative thing.
Uppercase DD is day of year. Lowercase hh is hour of AM or PM (1 through 12). Uppercase YYYY is weekbased year (only useful with week number). So you are asking for a date that is a Friday in May and the 19th day of the year. Obviously this is not possible.
The result of parsing is Thu Jan 05 23:00:00 CET 2017. Apparently SimpleDateFormat opts for giving you a Friday and for using the zone offset of 2 hours implied by CEST even though the date it has chosen is not at the time of year where CEST (summer time) is in use. I don’t know whether it just gives you the first Friday of the weekbased year (Friday in week 1 of the year). Friday at 0000 hours at offset GMT+2 equals Thursday at 23 at GMT+1, which is CET.
Next for the formatting, 05 is the date as expected, but lowercase mm means minutes. Since the minutes are 0, you get 00. You got the right year.
Rather than using the outdated classes that give you such surprises, I agree with Sam’s answer that you should use the newer classes in java.time:
ZonedDateTime dt = ZonedDateTime.parse(t,
DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US));
String s = dt.format(DateTimeFormatter.ofPattern("dd.MM.uuuu"));
This code gives you 19.05.2017 as you had expected. One of the good things about the modern classes is, if you try to parse with your original format pattern string, you will get a DateTimeParseException so you will know something is wrong. I certainly prefer an exception over incorrect output.
Another good thing is these classes respect the time zone in the input and use it in the output too (unless you explicitly instruct them otherwise). They will never turn Friday 6 January into Thursday 5 January because of some funny time zone issue.
Your input date is in Central European Summer Time and your date format is a bit wrong. Try
SimpleDateFormat input = new SimpleDateFormat("EEE MMM dd hh:mm:ss zzzz yyyy");
You might want to set the timezone on the output date format in order to get the date in the correct local time.
Ideally you'd move over to use a java.time style as shown here:
https://www.mkyong.com/java/java-convert-date-and-time-between-timezone/

Java SimpleDateFormat parsing irregularities

I'm doing some date parsing in Java and am encountering some weird behavior.
I have a date string such as follows:
String s = "Sun Aug 11 2013 11:00:00 -0700 (Pacific Daylight Time)"
I'm trying to parse it into a date object like so:
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss Z (zzzz)");
I then print out the resulting date object from sdf.parse(s) and get:
Sun Aug 11 12:00:00 CDT 2013
I am in the central time zone, so it makes sense that it prints it as such, however, CDT is -0500, so the parsed date should be 13:00, not 12:00.
The odd thing is, if I remove either of the redundant pieces of time zone information, the date parses correctly. Using the format "EEE MMM dd yyyy HH:mm:ss Z ('Pacific Daylight Time')" or the format "EEE MMM dd yyyy HH:mm:ss '-0700' (zzzz)" results in the correct date:
Sun Aug 11 13:00:00 CDT 2013
This behavior seems to only occur with dates that fall within daylight savings time. If I instead parse a date in, say, December, with my initial date format, I get the correct result.
I have somewhat limited control over the format of the dates I'm parsing, and they could be coming from a variety of time zones. Has anyone encountered this behavior before, and is there a way to get around it without changing the format of the date string? I realize the time zone designations are redundant, but they aren't incorrect as far as I can tell.
There have certainly been bugs in Java's handling of daylight saving time and time zones in the past, and this sure looks like one you've found. What version of Java is this?
You might want to try giving Joda-Time a try to see if it handles the given date correctly.
If Joda doesn't help, you might need to try pre-parsing some of that date string to remove the descriptive time zone in parenthesis since it works when only one is defined. Very strange indeed!

Getting date in GMT from unix timestamp [duplicate]

This question already has answers here:
How can I get the current date and time in UTC or GMT in Java?
(33 answers)
Closed 9 years ago.
I have written the following code to get the date in GMT from a unix timestamp
private Date converToDate(String unixTimeStamp)
{
//unix timestamps have GMT time zone.
DateFormat gmtFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
gmtFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
//date obtained here is in IST on my system which needs to be converted into GMT.
Date time = new Date(Long.valueOf(unixTimeStamp) * 1000);
String result = gmtFormat.format(time);
return lineToDate(result, true);
}
this code upon execution has
Mon May 27 02:57:32 IST 2013
value in the date variable and
Sun May 26 21:27:32 GMT 2013
in the result variable , How do I directly get the value in result variable into date variable ?
This is the problem, conceptually:
//date obtained here is in IST on my system which needs to be converted into GMT.
Date time = new Date(Long.valueOf(unixTimeStamp) * 1000);
A Date doesn't have a time zone. This is the value you want. The fact that when you call toString() it converts it to your local time zone is irrelevant to the value that it's actually representing. A Date is just a number of milliseconds since the Unix epoch (1st January 1970, midnight UTC). So your whole method can be:
private static Date convertToDate(String unixTimeStamp)
{
return new Date(Long.valueOf(unixTimeStamp) * 1000);
}
You don't need any kind of formatter, as you're not really trying to get a textual representation.
I would advise you to use Joda Time for date/time work if you can, by the way - it's a much cleaner API.
A Date is just the wrapper for a long, which contains a number of milliseconds.
What you're seeing is the default toString() representation of the Date object, which uses your default timezone (IST) to transform the date into a readable string. If you want the date represented as a string using the GMT timezone, just do what you did: use a date format with the GMT time zone.
The Date object represents an instant on the universal timeline, and doesn't have any timezone.

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.

How can I use Java's SimpleDateFormat to parse a timezone given as "GMT+0100 (BST)"?

I have a date that's in the form of:
Wed Aug 17 2011 09:57:09 GMT+0100 (BST)
and have a filter that takes a time in a certain format. The problem seems to be the time zone on the end, none of the format strings I'm putting in the filter seem to work for this type of date format.
For example,
Wed Aug 17 2011 09:57:09 GMT+0100 (BST)
EEE MMM dd yyyy HH:mm:ss zZ?
The time zone part of this, keeps throwing an error.
Can anyone tell me what the correct format to parse the time zones on these dates is?
"z" needs a colon between hours and minutes. "Z" is only +/-HHMM (i.e. no "GMT" prefix).
One way to parse it is: EEE MMM dd yyyy HH:mm:ss 'GMT'Z. The "BST" bit is ignored, and it's based on assumption that there's always "GMT" before offset.
I would parse out and interpret the time zone information separately, then use that to construct the Date/Calendar object in the proper time zone.
The following code seems to work well enough with your example:
String source = "Wed Aug 17 2011 09:57:09 GMT+0100 (BST)";
String tzid = "GMT" + source.substring(28, 31)
+ ":" + source.substring(31, 33);
TimeZone tz = TimeZone.getTimeZone(tzid);
// if (tz == null) ?
SimpleDateFormat f = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss");
f.setTimeZone(tz);
Date date = f.parse(source);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
System.out.println(date);
Prints "Wed Aug 17 08:57:09 UTC 2011".
A more sophisticated approach would be to use regex to extract individual parts ("+/-", "hh" and "mm") of the time zone offset.
Alternatively, you can attempt to discern the 3-letter time zone id (the string in between ( and )), and use the corresponding Java TimeZone if it exists.
In your particular example, though, "BST" resolves to Bangladesh Time which is GMT+0600 so you're better off with the numeric offset. "BST" here should probably be taken as British Summer Time (GMT+0100). This can be important because numeric offsets do not indicate the use of daylight savings time, which can be in effect depending on the date.
A more heuristic routine could take this into account and attempt to resolve the name first, but verify that the GMT offsets match, and fallback on the simple "GMT+hh:mm" timezones otherwise.
If you can not find a pattern matching your use case, try:
try{
new Date("Wed Aug 17 2011 09:57:09 GMT+0100 (BST)")
}catch(Exception e)
{
// Parse exception
}

Categories

Resources