Convert input String date time from different timezone to UTC - java

My system located in Singapore (timezone - "Asia/Singapore") receives a String datetime (yyyy-MM-dd HH:mm:ss) from a external system in Indonesia (timezone - "Asia/Jarkata").
How do I convert the received String datetime to UTC in java 1.7?
This is my code:
public void convertToUtc() {
String inputTime = "2018-02-02 10:09:00";
TimeZone inputTz = TimeZone.getTimeZone("Asia/Jarkarta");
TimeZone utcTz = TimeZone.getTimeZone("UTC");
SimpleDateFormat inputSdf = new SimpleDateFormat(DateTimeUtils.DATE_TIME_FORMAT);
inputSdf.setTimeZone(inputTz);
SimpleDateFormat utcSdf = new SimpleDateFormat(DateTimeUtils.ISO_DATE_TIME_FORMAT);
utcSdf.setTimeZone(utcTz);
// From time
Date fromDate = null;
try {
fromDate = inputSdf.parse(inputTime);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Convert to UTC
String sUtcDateTime = utcSdf.format(fromDate);
System.out.println("UTC: " + sUtcDateTime); // UTC: 2018-02-02T10:09:00.000Z. Expected 2018-02-02T03:09:00.000Z
}

janith1024’s answer is correct. However, I believe the real problem is that the old (and long outdated) TimeZone class behaves badly and doesn’t inform you of your spelling mistake. After all, we could all make that. So the real solution is to use java.time, the modern Java date and time API. On Java 7 (and 6) add ThreeTen Backport to your project, import:
import org.threeten.bp.ZoneId;
And then:
ZoneId inputTz = ZoneId.of("Asia/Jarkarta");
This gives you a org.threeten.bp.zone.ZoneRulesException: Unknown time-zone ID: Asia/Jarkarta. I should say that this greatly increases your chance of discovering your spelling error (the correct spelling is Asia/Jakarta).
The documentation of TimeZone.getTimeZone() says that it returns
the specified TimeZone, or the GMT zone if the given ID cannot be
understood.
However I am posting this answer because your issue is not just a lone example. Over and over we see questions on Stack Overflow coming from the old date and time classes showing surprising behaviour and in particular not detecting problems with the data we pass to them that it’s easy to detect. I very warmly recommend using the modern API instead.
In Java 8 and later, java.time is built-in, and you should import your date and time classes from java.time with subpackages rather than from org.threeten.bp.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.timeto Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.

I check your code there was a spelling mistake in time zone so I correct it
public static void convertToUtc() {
String inputTime = "2018-02-02 10:09:00";
TimeZone inputTz = TimeZone.getTimeZone("Asia/Jakarta");
TimeZone utcTz = TimeZone.getTimeZone("UTC");
SimpleDateFormat inputSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
inputSdf.setTimeZone(inputTz);
SimpleDateFormat utcSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
utcSdf.setTimeZone(utcTz);
// From time
Date fromDate = null;
try {
fromDate = inputSdf.parse(inputTime);
}
catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Convert to UTC
String sUtcDateTime = utcSdf.format(fromDate);
System.out.println("UTC: " + sUtcDateTime); // print this UTC: 2018-02-02 03:09:00.
}

Related

How to Compare UTC format converted date in java [duplicate]

I have two Date objects with the below format.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
String matchDateTime = sdf.parse("2014-01-16T10:25:00");
Date matchDateTime = null;
try {
matchDateTime = sdf.parse(newMatchDateTimeString);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// get the current date
Date currenthDateTime = null;
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Date dt = new Date();
String currentDateTimeString = dateFormat.format(dt);
Log.v("CCCCCurrent DDDate String is:", "" + currentDateTimeString);
try {
currenthDateTime = sdf.parse(currentDateTimeString);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Now I want to compare the above two dates along with time.
How should I compare in Java.
Thanks
Since Date implements Comparable<Date>, it is as easy as:
date1.compareTo(date2);
As the Comparable contract stipulates, it will return a negative integer/zero/positive integer if date1 is considered less than/the same as/greater than date2 respectively (ie, before/same/after in this case).
Note that Date has also .after() and .before() methods which will return booleans instead.
An Alternative is....
Convert both dates into milliseconds as below
Date d = new Date();
long l = d.getTime();
Now compare both long values
Use compareTo()
Return Values
0 if the argument Date is equal to this Date; a value less than 0 if this Date is before the Date argument; and a value greater than 0 if this Date is after the Date argument.
Like
if(date1.compareTo(date2)>0)
An alternative is Joda-Time.
Use DateTime
DateTime date = new DateTime(new Date());
date.isBeforeNow();
or
date.isAfterNow();
// Get calendar set to the current date and time
Calendar cal = Calendar.getInstance();
// Set time of calendar to 18:00
cal.set(Calendar.HOUR_OF_DAY, 18);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
// Check if current time is after 18:00 today
boolean afterSix = Calendar.getInstance().after(cal);
if (afterSix) {
System.out.println("Go home, it's after 6 PM!");
}
else {
System.out.println("Hello!");
}
The other answers are generally correct and all outdated. Do use java.time, the modern Java date and time API, for your date and time work. With java.time your job has also become a lot easier compared to the situation when this question was asked in February 2014.
String dateTimeString = "2014-01-16T10:25:00";
LocalDateTime dateTime = LocalDateTime.parse(dateTimeString);
LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault());
if (dateTime.isBefore(now)) {
System.out.println(dateTimeString + " is in the past");
} else if (dateTime.isAfter(now)) {
System.out.println(dateTimeString + " is in the future");
} else {
System.out.println(dateTimeString + " is now");
}
When running in 2020 output from this snippet is:
2014-01-16T10:25:00 is in the past
Since your string doesn’t inform of us any time zone or UTC offset, we need to know what was understood. The code above uses the device’ time zone setting. For a known time zone use like for example ZoneId.of("Asia/Ulaanbaatar"). For UTC specify ZoneOffset.UTC.
I am exploiting the fact that your string is in ISO 8601 format. The classes of java.time parse the most common ISO 8601 variants without us having to give any formatter.
Question: For Android development doesn’t java.time require Android API level 26?
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601

Changing the date format for a date range programmatically

I have an application where I want to change the date format in 'From' and 'To'.
Lets assume, I have a date range like 2018-06-11 - 2018-06-14. Now, I want to change it in some other format as 11 June, 2018 - 14 June, 2018.
Please refer the code below, I have tried:
String strDate = "2018-06-11 - 2018-06-14";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = format.parse(strDate);
format = new SimpleDateFormat("dd MMMM, yyyy");
String strFinalDate = format.format(date);
tv4.setText(strFinalDate);
} catch (ParseException e) {
e.printStackTrace();
}
Also, I tried the below code as well:
String strDate = "2018-06-11 - 2018-06-14";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd - yyyy-MM-dd");
try {
Date date = format.parse(strDate);
format = new SimpleDateFormat("dd MMMM, yyyy - dd MMMM, yyyy");
String strFinalDate = format.format(date);
tv4.setText(strFinalDate);
} catch (ParseException e) {
e.printStackTrace();
}
First, set of code runs smoothly, but converts only the 'From' and doesn't even checks for 'To' date.
And, second set of code returns an error which says, java.text.ParseException: Unparseable date: "2017-01-11 - 2017-01-14
Have I skipped anything in this code?
Please notify me if I have.
Thanks!
I suggest
DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG);
String strDate = "2018-06-11 - 2018-06-14";
String[] strDates = strDate.split(" - ");
if (strDates.length != 2) {
throw new IllegalStateException("Wrong range format " + strDate
+ ", must be yyyy-MM-dd - yyyy-MM-dd");
}
String strFinalDate = LocalDate.parse(strDates[0]).format(dateFormatter)
+ " - " + LocalDate.parse(strDates[1]).format(dateFormatter);
System.out.println(strFinalDate);
Output on my Java with US English locale:
11 June 2018 - 14 June 2018
You don’t get the comma after “June” because this is not considered standard, so consider if this isn’t really an advantage. The output will depend on locale setting, which may be an advantage too. Or specify explicit locale for example:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)
.withLocale(Locale.UK);
I am using and recommending java.time, the modern Java date and time API.
What went wrong in your code?
No matter if you use an old-fashiuoned Date or a modern LocalDate, such an object can only hold one date, not a date range. In your first attempt SimpleDateFormat parsed the first date (since it matched your pattern) and then ignored the remainder of the string. So when you formatted the parsed date, you got
11 June, 2018
In your seconds attempt both dates were parsed, but into the same Date object, so only the values of the second date were kept. When printing the date its values were also printed twice since the format pattern for formatting contains the format twice:
14 June, 2018 - 14 June, 2018
Question: Can I use java.time on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26, I’m told) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.timeto Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
As I stated in my comment above, you have to split your strDate String into two different String variables. Have a look at the code below
String strDate = "2018-06-11 - 2018-06-14";
String[] fromToDatesStr = strDate.split(" - ");
String fromDateStr = fromToDatesStr[0];
String toDateStr = fromToDatesStr[1];
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date fromDate = null;
Date toDate = null;
try {
fromDate = format.parse(fromDateStr);
toDate = format.parse(toDateStr);
format = new SimpleDateFormat("dd MMMM, yyyy");
String strFromFinalDate = format.format(fromDate);
String strToFinalDate = format.format(toDate);
} catch (ParseException e) {
e.printStackTrace();
}
String strFromFinalDate and String strToFinalDate now contain the dates formatted as you desire.

1 hour time difference daylight saving time issue

Function to convert server date to device local time:
public static String convertIntoLocalTime(String strTime, String whichTimeZone, String dateFormat) {
String strLocalTime = null;
try {
SimpleDateFormat sdf = getSimpleDateFormat(dateFormat, whichTimeZone);
Date date = sdf.parse(strTime);
AppLog.e(TAG,"Timezone = " + whichTimeZone);
AppLog.e(TAG,"Date = " + strTime);
AppLog.e(TAG,"Date in CET = " + date.toString());
AppLog.e(TAG,"inDaylightTime = " + sdf.getTimeZone().inDaylightTime(date));
AppLog.e(TAG,"DST savings = " + sdf.getTimeZone().getDSTSavings());
if (sdf.getTimeZone().getDSTSavings() == 3600000) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.HOUR, 1);
Date oneHourBack = cal.getTime();
SimpleDateFormat local = getLocalSimpleDateFormat(dateFormat);
strLocalTime = local.format(oneHourBack);
} else {
SimpleDateFormat local = getLocalSimpleDateFormat(dateFormat);
strLocalTime = local.format(date);
}
} catch (ParseException e) {
AppLog.e(TAG, e.getMessage(), e);
}
AppLog.e(TAG,"Local Time = " + strLocalTime);
return strLocalTime;
}
Function to get simple date format:
private static SimpleDateFormat getSimpleDateFormat(String format, String tz) {
TimeZone timeZone = TimeZone.getTimeZone(tz);
timeZone.useDaylightTime();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format, Locale.getDefault());
simpleDateFormat.setTimeZone(timeZone);
return simpleDateFormat;
}
Function to get simple date format for local device conversion:
/**
* #param format
* #return
*/
private static SimpleDateFormat getLocalSimpleDateFormat(String format) {
TimeZone timeZone = TimeZone.getDefault();
timeZone.useDaylightTime();
SimpleDateFormat localSdf = new SimpleDateFormat(format, Locale.getDefault());
localSdf.setTimeZone(timeZone);
return localSdf;
}
Output:
Date = 2018-04-22 14:30
Date in CET = Sun Apr 22 13:30:00 GMT+01:00 2018
inDaylightTime = true
DST savings = 3600000
Local Time = 2018-04-22 14:30
The above code was working perfectly fine earlier, for example we have 1 event on 1st of April where it was showing time correctly but at the moment starting from 21 April its showing additional 1 hour time.
I have tried to convert the date coming from server using UTC as well as CET but in both the cases its showing me additional one hour when converting it to device local time.
The above example is based on London timezone, whereas when we tried it in IST timezone it was returning the correct time.
We have handled DST time different by checking inDaylightTime function of timezone but it's not working.
I am sure that there is something related to DST but I am not able to figure it out. Thanks for your help?
First, you are using the old and long outdated date and time classes: SimpleDateFormat, Date, Calendar and TimeZone. These are renowned for being poorly designed and sometimes troublesome to work with. My first suggestion is you rewrite your code using java.time, the modern Java date and time API. It is much less buggy, and I expect that you will more easily develop correct code.
That said, no matter if you use the old-fashioned or the modern classes, don’t handle summer time yourself. The library classes will do it for you. Your job is to get the time zones correct. Don’t add or subtract an hour to compensate for summer time. Look at other questions about converting from one time zone to another, there are many.
Don’t use three and four letter time zone abbreviations. CET is not a time zone. IST is ambiguous, it may mean Irish Summer Time, Israel Standard Time or India Standard Time. The countries in Europe that use CET in winter have used CEST (Central European Summer Time) since March 26, 2018.
Instead give server time zone as continent/city such as Europe/London if this is the server time zone. It’s unambiguous.
Also make sure to set your device time zone to a true time zone. It seems you’ve got it set to GMT+01:00, which is a GMT offset, not a time zone. It agrees with Europe/London time zone and with CET in winter, but not after March 26.
Finally, you are adding 1 hour to your Calendar, turning it 1 hour forward, and then calling the Date you get from it oneHourBack. This looks wrong. Did you mean to subtract 1 hour, or did you mean that the variable should be oneHourForward?
EDIT: I probably haven’t understood exactly which time zones are the correct ones for you, and therefore not what would be the correct output for your code. So take the following only as a guess at what you were trying to accomplish. And please fill in the correct time zones.
public static String convertIntoLocalTime(
String strTime, String serverTimeZone, String dateFormat) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
ZonedDateTime serverDateTime = LocalDateTime.parse(strTime, formatter)
.atZone(ZoneId.of(serverTimeZone));
AppLog.e(TAG, "Server timezone = " + serverTimeZone);
AppLog.e(TAG, "Date = " + strTime);
AppLog.e(TAG, "Date in server timezone = " + serverDateTime.toString());
ZonedDateTime deviceTime = serverDateTime
.withZoneSameInstant(ZoneId.systemDefault());
String strLocalTime = deviceTime.format(formatter);
AppLog.e(TAG, "Device Time = " + deviceTime);
AppLog.e(TAG, "Local Time = " + strLocalTime);
return strLocalTime;
}
I tried setting my time zone to Europe/London and issuing the following call:
convertIntoLocalTime("2018-04-22 14:30", "Europe/Berlin", "yyyy-MM-dd HH:mm")
The output I got was:
Server timezone = Europe/Berlin
Date = 2018-04-22 14:30
Date in server timezone = 2018-04-22T14:30+02:00[Europe/Berlin]
Device Time = 2018-04-22T13:30+01:00[Europe/London]
Local Time = 2018-04-22 13:30
Question: Can I use java.time on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26, I’m told) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
List of tz database time zones
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.timeto Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
I was not tested so try it first.
public String convertIntoLocalTime(String strTime, String whichTimeZone, String dateFormat) {
String strLocalTime = null;
strLocalTime=convertDateToUserTimeZone(strTime,whichTimeZone,dateFormat);
return strLocalTime;
}
public String convertDateToUserTimeZone(String strTime, String whichTimeZone, String dateFormat) {
String ourdate;
try {
SimpleDateFormat formatter = new SimpleDateFormat(dateFormat, Locale.UK);
formatter.setTimeZone(TimeZone.getTimeZone(whichTimeZone));
Date value = formatter.parse(strTime);
TimeZone timeZone = TimeZone.getTimeZone("Asia/Kolkata");
SimpleDateFormat dateFormatter = new SimpleDateFormat(dateFormat, Locale.UK); //this format changeable
dateFormatter.setTimeZone(timeZone);
ourdate = dateFormatter.format(value);
//Log.d("OurDate", OurDate);
} catch (Exception e) {
ourdate = "00-00-0000 00:00";
}
return ourdate;
}

After parsing date string into Date and the converting it to millis, the output time is always lower on two hours

I am trying to parse a String with a date into a Date object and then convert it into millis.
But whatever I am doing - the output result in millis is always lower in 2 hours than the input date.
For example if the input date is 2018-1-10 11:30 - the output date will be 2018-01-10 9:30.
This is my code:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String dateString = "2018-1-10 11:30";
Date resultDate = sdf.parse(dateString);
long millis = resultDate.getTime();
// millis = 1515576600000
// When i am trying to convert millis to normal date via online
// converters i am always getting
// this result 10.01.18 9:30
I cannot understand why this is happening. How can I get back valid result after converting millis back? Why I got this difference in two hours?
It looks like a timezone problem.
Check in which timezone you are. If you are in UTC +02:00 the result is good !
If you want to set manually the timezone to match with UTC (without offset), check this stack overflow question: How to set time zone of a java.util.Date?
I hope this help you :)
One more example of where java.time, the modern Java date and time API, excels. It forces you to specify zone offset or time zone for operations like this one, which solves the problem:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-M-d H:mm");
String dateString = "2018-1-10 11:30";
long epochMillis = LocalDateTime.parse(dateString, dtf)
.atOffset(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
The result is 1515583800000 (maybe more readable as 1 515 583 800 000). Remove the last three zeros to convert to seconds and enter them on, for example, http://www.onlineconversion.com/unix_time.htm. The result is:
Wed, 10 Jan 2018 11:30:00 GMT
The GMT in the end confirms that the time is at the expected offset (for now we can consider GMT and UTC equivalent).
Question: Can I use java.time on Android?
You certainly can (I haven’t got the experience myself, though).
For the general Android market, use the Android edition of ThreeTen Backport (mentioned below). It’s called ThreeTenABP. Then import org.threeten.bp.format.DateTimeFormatter and org.threeten.bp.LocalDateTime.
For a newer Android device with Java 8 it should work out-of-the-box if you import java.time.format.DateTimeFormatter and java.time.LocalDateTime.
And on non-Android Java?
In Java 8 and later the new API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310).
Links
Oracle tutorial: Date Time, explaining how to use java.time.
ThreeTen Backport project
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Java Specification Request (JSR) 310, where the modern date and time API was first described.
By parsing the string it is assumed that the given time is based on your local time, whereas Date is in UTC. SimpleDateFormat does the conversion for you using your pcs time zone if you don't specify it.
https://docs.oracle.com/javase/7/docs/api/java/text/DateFormat.html#setTimeZone(java.util.TimeZone)
https://docs.oracle.com/javase/8/docs/api/java/util/Date.html
To convert it back you should use new Date (millis)
This considers your timezone as well and your result should be correct.
I think you are aware now that it is a timezone issue, but I figured I'll supply you a helper class that I wrote and use in most my applications as client server applications always have to take in account timezones and should be storing GMT on the server.
Hope this helps, you can copy and paste this class and handle a lot of your date formatting and timezone issues to and from the server.
public class DateHelper {
/*///////////////////////////////////////////////////////////////
// MEMBERS
*////////////////////////////////////////////////////////////////
public static SimpleDateFormat MY_APPS_CUSTOM_FORMATTER;
public final static String MMMM_dd = "MMMM, dd";
public final static String MMM_dd_yyyy = "MMM dd yyyy";
public final static String MMSlashddSlashyy = "MM/dd/yy";
public final static String MMSlashddSlashyy_hhColonmm_a = "MM/dd/yy hh:mm a";
public final static Calendar mCalender = Calendar.getInstance();
public final static TimeZone mLocalTimezone = mCalender.getTimeZone();
/*///////////////////////////////////////////////////////////////
// PROPERTIES
*////////////////////////////////////////////////////////////////
public synchronized static SimpleDateFormat getMyAppsDateCustomFormatter(boolean toServer, String format){
MY_APPS_CUSTOM_FORMATTER = new SimpleDateFormat(format);
if(toServer){
MY_APPS_CUSTOM_FORMATTER.setTimeZone(TimeZone.getTimeZone("UTC"));
}else{
MY_APPS_CUSTOM_FORMATTER.setTimeZone(mLocalTimezone);
}
return MY_APPS_CUSTOM_FORMATTER;
}
/*///////////////////////////////////////////////////////////////
// EXTRA HELPER METHODS
*////////////////////////////////////////////////////////////////
public static String getNowLocalTime(String formatToReturn){
return getMyAppsDateCustomFormatter(false, formatToReturn).format(new Date());
}
/*///////////////////////////////////////////////////////////////
// FROM SERVER FORMATTING
*////////////////////////////////////////////////////////////////
public static String getLocalDateStringFromGMTLong(long gmtTimestamp, String formatToReturn){
return getMyAppsDateCustomFormatter(false, formatToReturn).format(new Date(gmtTimestamp * 1000));
}
public static Date getDateFromLocalFormattedString(String date, String formatToUse, boolean toServer) throws Exception{
Date parsedDate = null;
try {
parsedDate = getMyAppsDateCustomFormatter(toServer, formatToUse).parse(date);
} catch (ParseException e) { //developer error, do NOT localize
throw new Exception(Globals.DEV_ERROR_STRINGS.INVALID_DATE_SUPPLIED_FOR_DEFAULT_FORMATTER);
}
return parsedDate;
}
public static String getFormattedStringFromLocalDate(Date date, String formatToUse) throws Exception{
return getMyAppsDateCustomFormatter(false, formatToUse).format(date);
}
/*///////////////////////////////////////////////////////////////
// TO SERVER FORMATTING
*////////////////////////////////////////////////////////////////
public static long getGMTLongFromLocalDate(Date date){
//Get Local Timezone
TimeZone tz = TimeZone.getDefault();
//Create new date for offset to GMT
Date ret = new Date(date.getTime() - tz.getRawOffset() );
// if we are now in DST, back off by the delta. Note that we are checking the GMT date, this is the KEY.
if ( tz.inDaylightTime( ret )){
Date dstDate = new Date( ret.getTime() - tz.getDSTSavings() );
// check to make sure we have not crossed back into standard time
// this happens when we are on the cusp of DST (7pm the day before the change for PDT)
if ( tz.inDaylightTime( dstDate )){
ret = dstDate;
}
}
return ret.getTime();
}
public static long getGMTLongFromLocalDateString(String date, String formatUsed) throws Exception {
Date passedDate = getDateFromLocalFormattedString(date, formatUsed, true);
//Get Local Timezone
TimeZone tz = TimeZone.getDefault();
//Create new date for offset to GMT
Date ret = new Date(passedDate.getTime() - tz.getRawOffset() );
// if we are now in DST, back off by the delta. Note that we are checking the GMT date, this is the KEY.
if ( tz.inDaylightTime( ret )){
Date dstDate = new Date( ret.getTime() - tz.getDSTSavings() );
// check to make sure we have not crossed back into standard time
// this happens when we are on the cusp of DST (7pm the day before the change for PDT)
if ( tz.inDaylightTime( dstDate )){
ret = dstDate;
}
}
return ret.getTime() / 1000;
}
public static long getNowGMTTime(){
return getGMTLongFromLocalDate(new Date());
}
}

Format ISO 8601 offset in Java [duplicate]

I have a date in the following format: 2010-03-01T00:00:00-08:00
I have thrown the following SimpleDateFormats at it to parse it:
private static final SimpleDateFormat[] FORMATS = {
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"), //ISO8601 long RFC822 zone
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"), //ISO8601 long long form zone
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"), //ignore timezone
new SimpleDateFormat("yyyyMMddHHmmssZ"), //ISO8601 short
new SimpleDateFormat("yyyyMMddHHmm"),
new SimpleDateFormat("yyyyMMdd"), //birthdate from NIST IHE C32 sample
new SimpleDateFormat("yyyyMM"),
new SimpleDateFormat("yyyy") //just the year
};
I have a convenience method that uses those formats like so:
public static Date figureOutTheDamnDate(String wtf) {
if (wtf == null) {
return null;
}
Date retval = null;
for (SimpleDateFormat sdf : FORMATS) {
try {
sdf.setLenient(false)
retval = sdf.parse(wtf);
System.out.println("Date:" + wtf + " hit on pattern:" + sdf.toPattern());
break;
} catch (ParseException ex) {
retval = null;
continue;
}
}
return retval;
}
It seems to hit on the pattern yyyyMMddHHmm but returns the date as Thu Dec 03 00:01:00 PST 2009.
What is the correct pattern to parse this date?
UPDATE: I don't NEED the time zone parsing. I don't anticipate having time sensitive issues moving between zones, but how would I get the "-08:00" zone format to parse????
Unit test:
#Test
public void test_date_parser() {
System.out.println("\ntest_date_parser");
//month is zero based, are you effing kidding me
Calendar d = new GregorianCalendar(2000, 3, 6, 13, 00, 00);
assertEquals(d.getTime(), MyClass.figureOutTheDamnDate("200004061300"));
assertEquals(new GregorianCalendar(1950, 0, 1).getTime(), MyClass.figureOutTheDamnDate("1950"));
assertEquals(new GregorianCalendar(1997, 0, 1).getTime(), MyClass.figureOutTheDamnDate("199701"));
assertEquals(new GregorianCalendar(2010, 1, 25, 15, 19, 44).getTime(), MyClass.figureOutTheDamnDate("20100225151944-0800"));
//my machine happens to be in GMT-0800
assertEquals(new GregorianCalendar(2010, 1, 15, 13, 15, 00).getTime(),MyClass.figureOutTheDamnDate("2010-02-15T13:15:00-05:00"));
assertEquals(new GregorianCalendar(2010, 1, 15, 18, 15, 00).getTime(), MyClass.figureOutTheDamnDate("2010-02-15T18:15:00-05:00"));
assertEquals(new GregorianCalendar(2010, 2, 1).getTime(), MyClass.figureOutTheDamnDate("2010-03-01T00:00:00-08:00"));
assertEquals(new GregorianCalendar(2010, 2, 1, 17, 0, 0).getTime(), MyClass.figureOutTheDamnDate("2010-03-01T17:00:00-05:00"));
}
Output from unit test:
test_date_parser
Date:200004061300 hit on pattern:yyyyMMddHHmm
Date:1950 hit on pattern:yyyy
Date:199701 hit on pattern:yyyyMM
Date:20100225151944-0800 hit on pattern:yyyyMMddHHmmssZ
Date:2010-02-15T13:15:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-02-15T18:15:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-03-01T00:00:00-08:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-03-01T17:00:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
JodaTime's DateTimeFormat to rescue:
String dateString = "2010-03-01T00:00:00-08:00";
String pattern = "yyyy-MM-dd'T'HH:mm:ssZ";
DateTimeFormatter dtf = DateTimeFormat.forPattern(pattern);
DateTime dateTime = dtf.parseDateTime(dateString);
System.out.println(dateTime); // 2010-03-01T04:00:00.000-04:00
(time and timezone difference in toString() is just because I'm at GMT-4 and didn't set locale explicitly)
If you want to end up with java.util.Date just use DateTime#toDate():
Date date = dateTime.toDate();
Wait for JDK7 (JSR-310) JSR-310, the referrence implementation is called ThreeTen (hopefully it will make it into Java 8) if you want a better formatter in the standard Java SE API. The current SimpleDateFormat indeed doesn't eat the colon in the timezone notation.
Update: as per the update, you apparently don't need the timezone. This should work with SimpleDateFormat. Just omit it (the Z) in the pattern.
String dateString = "2010-03-01T00:00:00-08:00";
String pattern = "yyyy-MM-dd'T'HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
Date date = sdf.parse(dateString);
System.out.println(date); // Mon Mar 01 00:00:00 BOT 2010
(which is correct as per my timezone)
if you used the java 7, you could have used the following Date Time Pattern. Seems like this pattern is not supported in the Earlier version of java.
String dateTimeString = "2010-03-01T00:00:00-08:00";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
Date date = df.parse(dateTimeString);
For More information refer to the SimpleDateFormat documentation.
Here's a snippet I used - with plain SimpleDateFormat. Hope somebody else may benefit from it:
public static void main(String[] args) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") {
public StringBuffer format(Date date, StringBuffer toAppendTo, java.text.FieldPosition pos) {
StringBuffer toFix = super.format(date, toAppendTo, pos);
return toFix.insert(toFix.length()-2, ':');
};
};
// Usage:
System.out.println(dateFormat.format(new Date()));
}
Output:
- Usual Output.........: 2013-06-14T10:54:07-0200
- This snippet's Output: 2013-06-14T10:54:07-02:00
Or... better, use a simpler, different, pattern:
SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
// Usage:
System.out.println(dateFormat2.format(new Date()));
Output:
- This pattern's output: 2013-06-14T10:54:07-02:00
See the docs for that.
Try this, its work for me:
Date date = javax.xml.bind.DatatypeConverter.parseDateTime("2013-06-01T12:45:01+04:00").getTime();
In Java 8:
OffsetDateTime dt = OffsetDateTime.parse("2010-03-01T00:00:00-08:00");
If you can use JDK 1.7 or higher, try this:
public class DateUtil {
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
public static String format(Date date) {
return dateFormat.format(date);
}
public static Date parse(String dateString) throws AquariusException {
try {
return dateFormat.parse(dateString);
} catch (ParseException e) {
throw new AquariusException(e);
}
}
}
document: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
which supports a new Time Zone format "XXX" (e.g. -3:00)
While JDK 1.6 only support other formats for Time Zone, which are "z" (e.g. NZST), "zzzz" (e.g. New Zealand Standard Time), "Z" (e.g. +1200), etc.
tl;dr
OffsetDateTime.parse( "2010-03-01T00:00:00-08:00" )
Details
The answer by BalusC is correct, but now outdated as of Java 8.
java.time
The java.time framework is the successor to both Joda-Time library and the old troublesome date-time classes bundled with the earliest versions of Java (java.util.Date/.Calendar & java.text.SimpleDateFormat).
ISO 8601
Your input data string happens to comply with the ISO 8601 standard.
The java.time classes use ISO 8601 formats by default when parsing/generating textual representations of date-time values. So no need to define a formatting pattern.
OffsetDateTime
The OffsetDateTime class represents a moment on the time line adjusted to some particular offset-from-UTC. In your input, the offset is 8 hours behind UTC, commonly used on much of the west coast of North America.
OffsetDateTime odt = OffsetDateTime.parse( "2010-03-01T00:00:00-08:00" );
You seem to want the date-only, in which case use the LocalDate class. But keep in mind you are discarding data, (a) time-of-day, and (b) the time zone. Really, a date has no meaning without the context of a time zone. For any given moment the date varies around the world. For example, just after midnight in Paris is still “yesterday” in Montréal. So while I suggest sticking with date-time values, you can easily convert to a LocalDate if you insist.
LocalDate localDate = odt.toLocalDate();
Time Zone
If you know the intended time zone, apply it. A time zone is an offset plus the rules to use for handling anomalies such as Daylight Saving Time (DST). Applying a ZoneId gets us a ZonedDateTime object.
ZoneId zoneId = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdt = odt.atZoneSameInstant( zoneId );
Generating strings
To generate a string in ISO 8601 format, call toString.
String output = odt.toString();
If you need strings in other formats, search Stack Overflow for use of the java.util.format package.
Converting to java.util.Date
Best to avoid java.util.Date, but if you must, you can convert. Call the new methods added to the old classes such as java.util.Date.from where you pass an Instant. An Instant is a moment on the timeline in UTC. We can extract an Instant from our OffsetDateTime.
java.util.Date utilDate = java.util.Date( odt.toInstant() );
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Thanks acdcjunior for your solution. Here's a little optimized version for formatting and parsing :
public static final SimpleDateFormat XML_SDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.FRANCE)
{
private static final long serialVersionUID = -8275126788734707527L;
public StringBuffer format(Date date, StringBuffer toAppendTo, java.text.FieldPosition pos)
{
final StringBuffer buf = super.format(date, toAppendTo, pos);
buf.insert(buf.length() - 2, ':');
return buf;
};
public Date parse(String source) throws java.text.ParseException {
final int split = source.length() - 2;
return super.parse(source.substring(0, split - 1) + source.substring(split)); // replace ":" du TimeZone
};
};
You can use X in Java 7.
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
static final SimpleDateFormat DATE_TIME_FORMAT =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
static final SimpleDateFormat JSON_DATE_TIME_FORMAT =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
private String stringDate = "2016-12-01 22:05:30";
private String requiredDate = "2016-12-01T22:05:30+03:00";
#Test
public void parseDateToBinBankFormat() throws ParseException {
Date date = DATE_TIME_FORMAT.parse(stringDate);
String jsonDate = JSON_DATE_TIME_FORMAT.format(date);
System.out.println(jsonDate);
Assert.assertEquals(jsonDate, requiredDate);
}
Try setLenient(false).
Addendum: It looks like you're recognizing variously formatted Date strings. If you have to do entry, you might like looking at this example that extends InputVerifier.
Since an example of Apache FastDateFormat(click for the documentations of versions:2.6and3.5) is missing here, I am adding one for those who may need it. The key here is the pattern ZZ(2 capital Zs).
import java.text.ParseException
import java.util.Date;
import org.apache.commons.lang3.time.FastDateFormat;
public class DateFormatTest throws ParseException {
public static void main(String[] args) {
String stringDateFormat = "yyyy-MM-dd'T'HH:mm:ssZZ";
FastDateFormat fastDateFormat = FastDateFormat.getInstance(stringDateFormat);
System.out.println("Date formatted into String:");
System.out.println(fastDateFormat.format(new Date()));
String stringFormattedDate = "2016-11-22T14:30:14+05:30";
System.out.println("String parsed into Date:");
System.out.println(fastDateFormat.parse(stringFormattedDate));
}
}
Here is the output of the code:
Date formatted into String:
2016-11-22T14:52:17+05:30
String parsed into Date:
Tue Nov 22 14:30:14 IST 2016
Note: The above code is of Apache Commons' lang3. The class org.apache.commons.lang.time.FastDateFormat does not support parsing, and it supports only formatting. For example, the output of the following code:
import java.text.ParseException;
import java.util.Date;
import org.apache.commons.lang.time.FastDateFormat;
public class DateFormatTest {
public static void main(String[] args) throws ParseException {
String stringDateFormat = "yyyy-MM-dd'T'HH:mm:ssZZ";
FastDateFormat fastDateFormat = FastDateFormat.getInstance(stringDateFormat);
System.out.println("Date formatted into String:");
System.out.println(fastDateFormat.format(new Date()));
String stringFormattedDate = "2016-11-22T14:30:14+05:30";
System.out.println("String parsed into Date:");
System.out.println(fastDateFormat.parseObject(stringFormattedDate));
}
}
will be this:
Date formatted into String:
2016-11-22T14:55:56+05:30
String parsed into Date:
Exception in thread "main" java.text.ParseException: Format.parseObject(String) failed
at java.text.Format.parseObject(Format.java:228)
at DateFormatTest.main(DateFormatTest.java:12)
If date string is like 2018-07-20T12:18:29.802Z
Use this
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

Categories