Java SimpleDateFormat interpret parse-string as UTC - java

my timezone is GMT+1.
so a "Date"-object with "22.09.1985 00:00UTC" prints "Sun Sep 22 01:00:00 CEST 1985" on the tostring function.
Now i'm trying to create this date by parsing "22/09/1985" with simpleDateFormat
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
sdf.setTimeZone(TimeZone.getDefault());
Date d = sdf.parse("22/09/1985");
=> Sun Sep 22 00:00:00 CEST 1985
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date d = sdf.parse("22/09/1985");
=> Sun Sep 22 02:00:00 CEST 1985
how can i configure simpledateformat that it creates an Date which prints "Sun Sep 22 01:00:00 CEST 1985" with input string "22/09/1985"?

My assumption was wrong,
22.09.1985 00:00UTC is actually 22.09.1985 02:00CET
so
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date d = sdf.parse("22/09/1985");
is exactly what i wanted, the date i compared it with was wrong.

Avoid java.util.Date & Calendar
You’ve found one of the many reasons to avoid using java.util.Date & .Calendar. They are notoriously troublesome. Either use Joda-Time or, in Java 8, the new java.time package which is inspired by Joda-Time and defined by JSR 310.
Search StackOverflow for "joda date" to find many examples.
Time Zone
You said:
my timezone is GMT+1.
Incorrect, your local offset from UTC/GMT is +01. That is not your time zone. A time zone is an offset plus rules about Daylight Saving Time (DST) and other anomalies.
And that offset should have two digits: +01 (or +01:00) rather than +1, according to the ISO 8601 standard.
Avoid the 3 or 4 letter codes such as CET. They are neither standardized nor unique. Use proper time zone names.
Generally speaking, you should specify a time zone in all your date-time work rather than rely on the current JVM's default.
In both Joda-Time and java.time, a date-time object truly knows its assigned time zone. A java.util.Date has no time zone, but seems to because its toString applies the default time zone when creating a String representation, as you sadly learned the hard way.
Example Code
Some code using Joda-Time 2.3.
String input = "22/09/1985";
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Amsterdam" );
DateTimeFormatter formatter = DateTimeFormat.forPattern( "dd/MM/yyyy" );
DateTime dateTime = formatter.withZone( timeZone ).parseDateTime( input );
DateTime dateTimeUtcGmt = dateTime.withZone( DateTimeZone.UTC );
DateTime dateTimeIndia = dateTime.withZone( DateTimeZone.forID( "Asia/Kolkata" ) );
String outputMontreal = DateTimeFormat.forStyle( "FF" ).withZone( DateTimeZone.forID( "America/Montreal" ) ).withLocale( Locale.CANADA_FRENCH ).print( dateTime );
// All of the above date-time represent the very same moment in the timeline of the Universe.
Dump to console…
System.out.println( "dateTime: " + dateTime );
System.out.println( "dateTimeUtcGmt: " + dateTimeUtcGmt );
System.out.println( "dateTimeIndia: " + dateTimeIndia );
System.out.println( "outputMontreal: " + outputMontreal );
When run…
dateTime: 1985-09-22T00:00:00.000+02:00
dateTimeUtcGmt: 1985-09-21T22:00:00.000Z
dateTimeIndia: 1985-09-22T03:30:00.000+05:30
outputMontreal: samedi 21 septembre 1985 18 h 00 EDT

The fact that you're parsing a date string, using a specific time zone, doesn't make the printed Date object to use that time zone. You're still using the same implementation of Date#toString(), which formats the Date object using the default timezone.
What you would need is to format your Date object with that SimpleDateFormat object. And if you have that specific string, then you would need another SimpleDateFormat object for parsing that string:
String dateString = "22/09/1985";
SimpleDateFormat parser = new SimpleDateFormat("dd/MM/yyyy");
Date parsedDate = parser.parse(dateString);
SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(formatter.format(parsedDate));
Java Date doesn't have the concept of TimeZone associated with it. You can only format a Date object using a specified timezone, and get a string. Or else, switch to JodaTime library.

Date is a relatively "dumb" class, as it just represents the number of milliseconds since 1970-01-01 00:00:00 UTC.
If you want to print out a Date as if it were a different timezone, you need to construct a DateFormat / SimpleDateFormat for that TimeZone and format it to a String that way.

Related

Getting an Unparseable date error while calculating difference between Current date/time and Start date/time for an user in Sailpoint

Getting an Unparseable date error while calculating difference between Current date/time and Start date/time for an user.
Error: java.text.ParseException: Unparseable date: "09/11/20 00:00:00 AM CDT" at java.base/java.text.DateFormat.parse(DateFormat.java:395)
I get this error at line no.8, which is
String output2 = sdf1.format((sdf1.parse(startDate)).getTime());
'dateDifference' is a library used to calculate the difference between the current date/time and the start date/time of an user.
if(link.getAttribute("lastLogonTimeStamp")== null){
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Calendar cur_time = Calendar.getInstance();
cur_time.setTime(new Date());
String output = sdf.format(cur_time.getTime());
System.out.println(" +++++ Output +++++" + output);
SimpleDateFormat sdf1 = new SimpleDateFormat("MM/dd/yy HH:mm:ss a zzz");
String output2 = sdf1.format((sdf1.parse(startDate)).getTime());
System.out.println(" +++++ Start Date +++++" + output2);
int diff = dateDifference(output2);
System.out.println(" +++++ Difference +++++" + diff);
if(diff>0){
System.out.println("Start Date is not a Future Date :" + startDate);
bw.write(id.getName()+","+ntID+","+id.getFirstname() +" "+id.getLastname() +","+id.getEmail()+ "," + id.getAttribute("empType")+ "," +lastLoginDt+ ","+mgrName+","+(String)id.getAttribute("startDate")+","+(String)id.getAttribute("title")+"\n");
count++;
}
}
tl;dr
I would not accept such a poor input string into my own app. But if you insist, you can try to parse ambiguous input such as CDT but this is a guessing game that may fail depending on the input.
ZonedDateTime.parse(
"09/11/20 00:00:00 AM CDT" ,
DateTimeFormatter.ofPattern( "MM/dd/uu HH:mm:ss a z" )
)
Parsing
CDT is not a real time zone. It is a localized indicator of whether Daylight Saving Time (DST) is effect.
Do not use localized formats for data exchange. Use localized values only for presentation to the user. For data exchange, use only ISO 8601 standard formats. The standard was invented for just that purpose, data exchange. The java.time classes use the standard formats by default when parsing/generating strings, so no need to specify formatting patterns.
Do not use Calendar and SimpleDateFormat classes. These terrible date-time classes are now legacy, years ago supplanted by the modern java.time classes defined in JSR 310. Search to learn more as this has been covered many many times already on Stack Overflow.
You can ask DateTimeFormatter class to guess what CDT might mean. But those pseudo-zone values are not standardized, and are not even unique! For example CST might mean "China Standard Time" or might mean "Central Standard Time" (in North America).
I recommend against accepting such poor inputs as yours, as playing guessing games in your code makes for unreliable apps. But if you insist:
String input = "09/11/20 00:00:00 AM CDT";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uu HH:mm:ss a z" );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
zdt.toString() = 2020-09-11T00:00-05:00[America/Chicago]
The text generated by ZonedDateTime#toString is actually an extension to the ISO 8601 standard format, appending the name of the zone in square brackets.
Calculating elapsed time
Apparently you want to calculate the amount of time elapsed between the moment represented by your input and the current moment.
To calculate elapsed time in terms of hours-minutes-seconds, use Duration while capturing the current moment as seen in UTC (an offset from UTC of zero hours-minutes-seconds).
Duration elapsed = Duration.between( zdt.toInstant() , Instant.now() ) ;
To calculate elapsed time in terms of years-months-days, use Period. Access the time zone contained in our ZonedDateTime to get the same timeframe.
Period elapsed = Period.between( zdt , ZonedDateTime.now( zdt.getZone() ) ;
I have rewritten the code in the below format and that worked.
if(lastLogon == null || lastLogon.equalsIgnoreCase("never")){
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Calendar cur_time = Calendar.getInstance();
cur_time.setTime(new Date());
String output = sdf.format(cur_time.getTime());
SimpleDateFormat dateParser = new SimpleDateFormat("MM/dd/yy HH:mm:ss a zzz");
Date date = dateParser.parse(startDate);
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
String output2 = dateFormatter.format(date);
int diff = dateDifference(output2);
if(diff>0){}

Timestamp string to timestamp in java

I have the following string "2015-04-02 11:52:00+02" and I need to parse it in Java to a Timestamp.
I tried all sorts of formats including
SimpleDateFormat mdyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+Z");
but nothing seems to work - I keep getting a ParseException
Can anyone help?
I need something like:
SimpleDateFormat mdyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+Z");
Timestamp t = new Timestamp(mdyFormat.parse("2015-04-02 11:52:00+02").getTime());
Try This
String str="2009-12-31 23:59:59 +0100";
/\
||
Provide Space while providing timeZone
SimpleDateFormat mdyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
System.out.println(mdyFormat.parse(str));
Output
Fri Jan 01 04:29:59 IST 2010
java.sql.Timestamp objects don't have time zones - they are instants in time, like java.util.Date
So try this:
SimpleDateFormat mdyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Timestamp t = new Timestamp(mdyFormat.parse("2015-04-02 11:52:00").getTime());
try "yyyy-MM-dd HH:mm:ssX"
Z stand for timezone in the following format: +0800
X stand for timezone in the following format: +08
Examples here
ISO 8601
Replace that SPACE in the middle with a T and you have a valid standard (ISO 8601) string format that can be parsed directly by either the Joda-Time library or the new java.time package built into Java 8 (inspired by Joda-Time). Search StackOverflow for hundreds of examples.
If using java.time, read my comment on Question about a bug when parsing hours-only offset value.
Example in Joda-Time 2.7.
String inputRaw = "2015-04-02 11:52:00+02";
String input = inputRaw.replace( " ", "T" );
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" ); // Specify desired time zone adjustment.
DateTime dateTime = new DateTime( input, zone );

Java Date forcing BST "timezone"

In JAVA, how can I make sure that all dates are returned as GMT dates ?
For example, even if I try to force a DateFormat with GMT locale, it's applying some sort of logic that retrieves a BST date.
public static void main(String[] args) throws ParseException {
DateFormat dd = new SimpleDateFormat("MMM dd HH:mm:ss zzz yyyy");
dd.setTimeZone(TimeZone.getTimeZone("GMT"));
Date parse = dd.parse("Out 29 23:00:00 GMT 2011");
Date parse2 = dd.parse("Out 30 23:00:00 GMT 2011");
System.out.println(parse); // Prints "Sun Oct 30 00:00:00 BST 2011"
System.out.println(parse2); // Prints "Sun Oct 30 23:00:00 GMT 2011"
System.out.println(Locale.getDefault()); // Prints "en_US"
System.out.println(TimeZone.getDefault().getID()); // Prints "Europe/London"
}
Where is the BST coming from ? Is it related to daylight saving times ? TimeZone class says otherwwise.
System.out.println(TimeZone.getTimeZone("GMT").inDaylightTime(parse)); // Prints "false"
System.out.println(TimeZone.getTimeZone("GMT").inDaylightTime(parse2)); // Prints "false"
The default system locale is en_US.
Edit: Based on Basil Bourque's response, I can get both prints to GMT dates, if I change the default time zone to GMT:
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
Mystery
Are you sure your comments on both System.out.println lines are correct? I expect output from both lines to have the same time zone, either BST or GMT.
If you are certain those are correct, please post a complete example of working code. Also document your default locale and time zone.
Fully Working Example
Here is my version of your code transformed into a fully working example. I deduce from the BST and out that this is Portuguese Brazil locale.
java.util.Locale.setDefault( new Locale.Builder().setLanguage( "pt" ).setRegion( "BR" ).build() ); // **HACK* Think twice before ever setting the default of your JVM’s locale or time zone. Generally a bad idea.
java.text.DateFormat dd = new java.text.SimpleDateFormat( "MMM dd HH:mm:ss zzz yyyy" );
dd.setTimeZone( java.util.TimeZone.getTimeZone( "GMT" ) );
Date parse = null;
Date parse2 = null;
try {
parse = dd.parse( "Out 29 23:00:00 GMT 2011" );
parse2 = dd.parse( "Out 30 23:00:00 GMT 2011" );
} catch ( ParseException ex ) {
Logger.getLogger( JodaTimeWork.class.getName() ).log( Level.SEVERE , null , ex );
}
System.out.println( parse );
System.out.println( parse2 );
My output when running on a US locale and America/Los_Angeles time zone, thus the PDT time zone.
Sat Oct 29 16:00:00 PDT 2011
Sun Oct 30 16:00:00 PDT 2011
No Time Zone On A Date Object
Be aware that a java.util.Date object has no time zone assigned†. Confusingly, the toString method implementation on that class applies the JVM’s current default time zone. So it seems like the Date object has a time zone, but it does not.
As the correct comment by GriffeyDog said, the DateFormat object has a time zone but the Date object does not.
So I expect both of your System.out.println lines to emit text with the same time zone, as I said up top.
Joda-Time | java.time
This confusing handling of time zones is one of many reasons to avoid java.util.Date/.Calendar & SimpleTextFormat. Those in the know use either the Joda-Time library or the new java.time package built into Java 8. The java.time package was inspired by Joda-Time but is re-architected; each has its strengths and weaknesses.
Example in Joda-Time
Here is an example in Joda-Time 2.7.
Time Zone on DateTime
A DateTime object in Joda-Time knows its own assigned time zone, unlike a java.util.Date object.
Incorrect Localization
Your input data’s use of an uppercase O for Out appears to be incorrect for Portuguese convention. My example corrects that to be lowercase. Joda-Time rejects the uppercase as invalid.
Code
String input1 = "out 29 23:00:00 GMT 2011";
String input2 = "out 30 23:00:00 GMT 2011";
Locale locale_pt_BR = new Locale.Builder().setLanguage( "pt" ).setRegion( "BR" ).build(); //
DateTimeFormatter formatter = DateTimeFormat.forPattern( "MMM dd HH:mm:ss 'GMT' yyyy" ).withLocale( locale_pt_BR ).withZone( DateTimeZone.UTC );
DateTime dateTime1 = null;
DateTime dateTime2 = null;
DateTime dateTime1_Sao_Paulo = null;
DateTime dateTime2_Sao_Paulo = null;
try {
dateTime1 = formatter.parseDateTime( input1 );
dateTime2 = formatter.parseDateTime( input2 );
// Adjust to "America/Sao_Paulo" time zone.
DateTimeZone zone_Sao_Paulo = DateTimeZone.forID( "America/Sao_Paulo" );
dateTime1_Sao_Paulo = dateTime1.withZone( zone_Sao_Paulo );
dateTime2_Sao_Paulo = dateTime2.withZone( zone_Sao_Paulo );
} catch ( IllegalArgumentException e ) {
// … Handle exception.
System.out.println( "ERROR - Unexpected input for parsing into a date-time object." );
}
Dump to console.
System.out.println( "dateTime1 : " + dateTime1 );
System.out.println( "dateTime2 : " + dateTime2 );
System.out.println( "Adjusted to America/Sao_Paulo: " + dateTime1_Sao_Paulo + " & " + dateTime2_Sao_Paulo );
When run.
dateTime1 : 2011-10-29T23:00:00.000Z
dateTime2 : 2011-10-30T23:00:00.000Z
Adjusted to America/Sao_Paulo: 2011-10-29T21:00:00.000-02:00 & 2011-10-30T21:00:00.000-02:00
ISO 8601
If you have any control or influence on the format of your input data, I strongly suggest changing to the standard ISO 8601 format.
Example: 2015-02-15T19:39:11Z.
Time Zone
Avoid the 3 or 4 letter codes for time zones. They are neither standardized nor unique. BST for example can be:
British Summer Time (outdated as of 1971 but still tops in Google hits)
Brazil Standard Time
Bangladesh Standard Time
Use proper time zone names. Example: America/Sao_Paulo.
3-4 Letter Codes Refused By Joda-Time
Because of the frequent duplicate values, it is impossible to responsibly parse such values. So Joda-Time refuses to try.
Note in the example code above how I hard-coded the expected GMT value. See the single-quote marks (APOSTROPHE) around the "GMT" letters. That tells Joda-Time to expect and ignore that string while parsing.
This has a crucial consequence: With no identified time zone or offset-from-UTC, Joda-Time does not know how to interpret the date-time when parsing the string. We set the formatter to a time zone by which to interpret the string with no time zone or offset. If the string did have an offset, setting a time zone on the formatter has a different behavior: after parsing, the formatter adjusts the value to that time zone.
† Even more confusing, the java.util.Date actually does have a time zone, but buried deep within its implementation. That time zone is ignored for most practical purposes. So as shorthand, we say a j.u.Date has no time zone (effectively acts as if in UTC).

Convert 24 Hour Time in to 12 Hour Time in Java

I want to convert 24 Hour time into 12 Hour AM/PM time.
e.g:- How to convert date 2012-03-20T22:30:00.000+05:30 to to 2012-03-20 10:30 PM??
I have extratced the date but its in 24 Hour time. I though used SimpleDateFormater but still for 12.30 it is showing 00.30 and not 12.30 PM.
Thanks in advance.
Try this:
String dateStr = new SimpleDateFormat("yyyy-MM-dd hh:mm a").format(new Date());
The bundled java.util.Date and .Calendar classes are notoriously troublesome. Avoid them. Use either Joda-Time or the new java.time package in Java 8.
Joda-Time
DateTimeZone timeZone = DateTimeZone.ForID( "Asia/Kolkata" );
DateTime dateTime = new DateTime( "2012-03-20T22:30:00.000+05:30", timeZone );
Java.util.Locale locale = java.util.Locale.Builder().setLanguage("en").setRegion("IN").build();
DateTimeFormatter formatter = DateTimeFormat.forStyle( "SS" ).withLocale( locale).withZone( timeZone );
String output = formatter.print( dateTime );

How to convert date and time to user timezone

Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("PST"));
cal.setTime(new Date());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");
Date resultdate = new Date(cal.getTimeInMillis());
sdf.setTimeZone(TimeZone.getTimeZone("PST"));
System.out.println("String date:"+sdf.format(resultdate));
System.out.println("Date:"+sdf.parse(sdf.format(resultdate)));
output:
String date:2011-12-29 09:01:58 PM
Date:Fri Dec 30 10:31:58 IST 2011
Problem:
sdf.format(resultdate) returning correct date and time to as per timezone. But,
sdf.parse(sdf.format(resultdate)) not returning correct date and time to as per timezone, how to fix this problem?
The Date class is merely a thin wrapper around the number of milli-seconds past the 'epoch' (January 1, 1970, 00:00:00 GMT). It doesn't store any timezone information. In your last call you are adding a date instance to a String which implicitly calls the toString() method. The toString() method will use the default timezone to create a String representing the instance (as it doesn't store any timezone info). Try modifying the last line to avoid using the toString() method.
System.out.println("Date:" + sdf.format(sdf.parse(sdf.format(resultdate))));
Try using joda-Time api for your convenience. Example is here
Unfortunatley Java date returns time in GMT only. When ever you want display in front end or some where, you need to use the formated String generated in your step1.
try the below code will, it will work.
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("PST"));
cal.setTime(new Date());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");
Date resultdate = new Date(cal.getTimeInMillis());
sdf.setTimeZone(TimeZone.getTimeZone("PST"));
System.out.println("String date:"+sdf.format(resultdate));
System.out.println("Date:"+sdf2.parse(sdf.format(resultdate)));
Three-Letter Time Zone Codes
Avoid using the three-letter time zone codes. They are neither standardized nor unique. For example, IST means both India Standard Time and Irish Standard Time. Furthermore, the codes are meant to distinguish Daylight Saving Time (DST) but that only confuses matters.
Use proper descriptive time zone names to retrieve a time zone object that encompasses DST and other issues.
Joda-Time
The java.util.Date & Calendar classes bundled with Java are notoriously troublesome. Avoid them. Use Joda-Time or the new java.time.* package bundled with Java 8.
In JodaTime, a DateTime object truly knows its own time zone (unlike java.util.Date). Usually we use the immutable classes in Joda-Time. So instead of changing the time zone in a DateTime object, we create a fresh new DateTime object based on the old but with a specified difference. A different time zone might be that difference.
Here is some example code.
DateTimeZone timeZone_India = DateTimeZone.forID( "Asia/Kolkata" );
DateTimeZone timeZone_Ireland = DateTimeZone.forID( "Europe/Dublin" );
DateTimeZone timeZone_US_West_Coast = DateTimeZone.forID( "America/Los_Angeles" );
DateTime now = new DateTime( timeZone_India );
System.out.println( "now in India: " + now );
System.out.println( "now in Ireland: " + now.withZone( timeZone_Ireland ) );
System.out.println( "now in US West Coast: " + now.withZone( timeZone_US_West_Coast ) );
System.out.println( "now in UTC/GMT: " + now.withZone( DateTimeZone.UTC ) );
When run…
now in India: 2014-02-10T13:52:27.875+05:30
now in Ireland: 2014-02-10T08:22:27.875Z
now in US West Coast: 2014-02-10T00:22:27.875-08:00
now in UTC/GMT: 2014-02-10T08:22:27.875Z
java.time
Same idea using the java.time classes which supplant Joda-Time.
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instant = Instant.now();
Apply a time zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
The instant and the zdt represent the same moment, the same point on the timeline. Each is seen through the lens of a different region’s wall-clock time.
Generate a String by either specifying a formatting pattern or by letting java.time automatically localize.
To localize, specify:
FormatStyle to determine how long or abbreviated should the string be.
Locale to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, and such.
Example:
Locale l = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( l );
String output = zdt.format( f );

Categories