Gson deserialize Java.util.Date with timezone - java

I deserialize a json string with date:
"created_at": "2015-12-24T17:41:54+01:00",
I set date format for gsonBuilder:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").create();
The deserialization works without crash; unfortunately when I print the result it's not correct:
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ssZ");
String str = ft.format(response.createdAt);
The result is:
2015-12-24T11:41:54-0500
instead of:
2015-12-24T17:41:54+01:00

You haven't set the timezone only added a Z to the end of the date/time, so it will look like a GMT date/time but this doesn't change the value.
Set the timezone to GMT and it will be correct.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

java.time
The accepted Answer is correct. But outdated. The java.text.SimpleDateFormat and java.util.Date classes have been outmoded by the java.time framework added to Java 8 and later. Much easier to use and more sensible.
ISO 8601
The format of your input string complies with the ISO 8601 standard. The java.time classes use ISO 8601 as their default formats when parsing/generating string representations of date-time values.
String input = "2015-12-24T17:41:54+01:00";
Offset-From-UTC
That input string includes an offset-from-UTC of +01:00, meaning an hour ahead of UTC.
ZonedDateTime zdt = ZonedDateTime.parse ( input );
ZoneId z = zdt.getZone ();
Offset versus Time Zone
But that offset is not a time zone. A time zone is an offset plus rules for handling anomaly adjustments such as Daylight Saving Time (DST). So you may well want to assign a specific time zone you have in mind as being intended by that string. Perhaps you intended Amsterdam time.
We can apply a time zone to get another ZonedDateTime object. This pattern of creating a new object based on an old object’s values rather than changing the old values directly is known as immutable objects.
A ZoneId is a full time zone in java.time. Its subclass ZoneOffset is for simple offset-from-UTC values without the adjustment rules.
ZoneId zoneIdAmsterdam = ZoneId.of ( "Europe/Amsterdam" );
ZonedDateTime zdtAmsterdam = zdt.withZoneSameInstant ( zoneIdAmsterdam );
toString
When you call toString such as in a System.out.println, java.time classes generate a String representation of the date-time value using ISO 8601 format.
Note that java.time extends ISO 8601 by appending the name of an assigned time zone in square brackets in addition to the offset-from-UTC number. For example, [Europe/Amsterdam].
System.out.println ( "zdt: " + zdt + " at zoneId z: " + z + " adjusted to zoneIdAmsterdam: " + zoneIdAmsterdam + " is zdtAmsterdam: " + zdtAmsterdam );
zdt: 2015-12-24T17:41:54+01:00 at zoneId z: +01:00 adjusted to zoneIdAmsterdam: Europe/Amsterdam is zdtAmsterdam: 2015-12-24T17:41:54+01:00[Europe/Amsterdam]
Instant
Generally in our business logic and data storage we work strictly in UTC, applying a time zone only for presentation to the user. For this purpose, pass and store an instance of the Instant class. This class represents a moment on the timeline in UTC.
Instant instant = zdt.toInstant();

Related

Java: convert string to different time zone

I've tried all sorts of different conversions with different Java formatters but I'm still not having any luck with something that seems simple.
I have a string that is a date/time in UTC. I'm trying to convert that to another time zone. Is any one able to tell me why the below isn't working? The time zone is changing but it's not changing the right way.
Updated: (though it doesn't seem like I'm setting the time zone to UTC properly as the conversion isn't correct either).
String dateInput = "2021-02-16 20:57:43";
SimpleDateFormat mdyUtc = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
mdyUtc.setTimeZone(TimeZone.getTimeZone("UTC");
Date utcOutput = mdyUtc.parse(dateInput);
SimpleDateFormat mdyOffset = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
mdyOffset.setTimeZone(TimeZone.getTimeZone("GMT-10:00");
Date localOutput = mdyOffset.parse(dateInput);
System.out.print("UTC date = " + utcOutput);
System.out.print("Changed date = " + localOutput);
Output:
UTC date = Tue Feb 16 15:57:43 EST 2021
Changed date = Wed Feb 17 01:57:43 EST 2021
java.time
The java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API*.
Using the modern date-time API:
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String dateInput = "2021-02-16 20:57:43";
// Replace ZoneId.systemDefault() with ZoneOffset.UTC if this date-time is in UTC
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d H:m:s", Locale.ENGLISH)
.withZone(ZoneId.systemDefault());
ZonedDateTime zdt = ZonedDateTime.parse(dateInput, dtf);
ZonedDateTime result = zdt.withZoneSameInstant(ZoneId.of("GMT-10:00"));
System.out.println(result);
}
}
Output:
2021-02-16T10:57:43-10:00[GMT-10:00]
ONLINE DEMO
Learn more about the modern date-time API from Trail: Date Time.
Can I get java.util.Date from ZonedDateTime?
If at all you need to use java.util.Date, you can convert ZonedDateTime into it as follows:
Date date = Date.from(result.toInstant());
Note that the java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). When you print an object of java.util.Date, its toString method returns the date-time in the JVM's timezone, calculated from this milliseconds value. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFormat and obtain the formatted string from it.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
tl;dr
LocalDateTime // Represent a date with time-of-day but lacking the context of a time zone or offset-from-UTC.
.parse( // Interpret some text in order to build a date-time object.
"2021-02-16 20:57:43".replace( " " , "T" ) // Convert to standard ISO 8601 string to parse by default without needing to specify a formatting pattern.
) // Returns a `LocalDateTime` object.
.atOffset( // Place that date with time into the context of an offset. Determines a moment, a specific point on the timeline.
ZoneOffset.UTC // A constant for an offset of zero hours-minutes-seconds.
) // Returns an `OffsetDateTime` object.
.atZoneSameInstant( // Adjust the view of this moment as seen in the wall-clock time of some other time zone. Still the same moment, same point on the timeline.
ZoneId.of( "Pacific/Honolulu" ) // Use a time zone, if known, rather than a mere offset.
) // Returns a `ZonedDateTime` object.
.toString() // Generate text representing this moment in standard ISO 8601 format extended to append the time zone name in square brackets.
See this code run live at IdeOne.com.
2021-02-16T10:57:43-10:00[Pacific/Honolulu]
Details
The Answer by Avinash is correct, using a DateTimeFormatter with an assigned ZoneId. That works, but I prefer keeping the zone assignment separate from the formatter, to be more explicit to someone reading the code. This is only about my preference, not about correctness; both Answers are equally correct.
Parse your input as a LocalDateTime, as the input represents a date with time-of-day but lacks any indication of offset or time zone.
By default, the java.time classes use standard text formats defined in ISO 8601. If an input complies, no need to specify a formatting pattern. To comply, replace your input’s SPACE character in the middle with a T.
String input = "2021-02-16 20:57:43".replace( " " , "T" ) ;
LocalDateTime ldt = LocalDateTime.parse( input ) ;
You said you know for certain that input was meant to represent a date with time as seen in UTC, having an offset-from-UTC of zero hours-minutes-seconds. So we can apply an offset of zero using ZoneOffset to produce a OffsetDateTime.
Also, I suggest you educate the publisher of your data feed about using ISO 8601 formats to communicate that offset-of-zero fact by appending a Z (as well as using T in the middle).
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ; // Place date with time into context of an offset of zero.
Lastly, you said you want to adjust that moment to another time zone. Apply a ZoneId to get a ZonedDateTime object.
Actually, you specified an offset of "GMT-10:00". But it is better to use a time zone if known rather than a mere offset. A time zone is a history of past, present, and future changes to the offset used by the people of a particular region.
I will guess you want Hawaii time, Pacific/Honolulu.
ZoneId z = ZoneId.of( "Pacific/Honolulu" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
The java.util.Date API is deprecated; you should look into the new Date and Time APIs around LocalTime et al.
That said, if you want to keep the old code: It is a bit brittle. Your initial date input does not specify a time zone, so you'll probably get the system's time zone. You should specify a time zone --- if the expected input is UTC, say so.
Then you need to specify the time zone either in an hour offset or with a name, not both.
When I change your code to use
mdyOffset.setTimeZone(TimeZone.getTimeZone("-10:00"));
I get
Changed date = Tue Feb 16 14:57:43 CST 2021
which seems to fit, as I'm on CST (currently 6 hours after GMT), so 20:57:43 minus 6 is 14:57:43. Again, this is displayed in my local time zone. You may have to use a DateFormat to adjust the output as needed.

java check a Date instance has the time part

I have a Date field in my class that can has two types of values: with and without time. Something like this: 2015-01-01 and 2015-01-01 12:00:00. I want to make formatted string from my date. I know I can use SimpleDateFormat class for doing this, but I don't know the format. In fact, If my date has the time part, I must use yyyy-MM-dd HH:mm:ss format and if my date does not have the time part, I must use yyyy-MM-dd format. My question is, Is there anyway to check a date has time section before formatting it?
Here is my code:
private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
.....
private String formatDate(Date date){
//I need to something like this:
if(/* `date` has time part */){
return dateTimeFormat.format(date);
}
else{
return dateFormat.format(date);
}
}
You cannot reliably do that, because once you create a Date object, it is represented as a number in milliseconds, which includes the specific time. For this reason you cannot possibly know how the object was built and if the specific time was set.
A workaround would be to check if the hours, minutes and seconds are set to zero. Keep in mind that there is a small probability that the date was parsed as "yyyy-MM-dd HH:mm:ss", but all these values were set to 0, simply because the time was indeed 00:00:00. However, this probability is equal to 1 / (24 * 60 * 60) = 0.00001157407, so I assume that you can live with that.
A Big Mess
As shown in the other answers, the old date-time classes bundled with Java such as java.util.Date and java.sql.Date are a mess. They were rushed to market, with bad design decisions. Specifically a java.util.Date represents both a date and a time-of-day, while its subclass java.sql.Date pretends not to have a time-of-day but actually does. The doc explains that you are supposed to ignore this inheritance relationship to help maintain the illusion. Not good.
java.time
This whole mess has been supplanted by the java.time framework built into Java 8 and later. The new classes are inspired by the highly successful Joda-Time framework, intended as its successor, similar in concept but re-architected. Defined by JSR 310. Extended by the ThreeTen-Extra project. See the Tutorial.
Date-Only
Among the new classes is LocalDate. This is the first class bundled with Java for representing a date only, without time-of-day nor time zone. To determine a date such as "today", you need a time zone (a ZoneId). For example, a new day dawns earlier in Paris than in Montréal. When you need a date-only value, I suggest you add a member to your class of this type.
LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
Date-Time
If you want a date-time, first consider the Instant class. This marks a moment on the timeline in UTC. Almost always best to do your business logic and data storage in UTC. When you need a specific moment in time rather than a vague date, add a member of this type to your class.
Instant now = Instant.now();
For presentation to the user in their desired/expected time zone, apply a time zone to an Instant to get a ZonedDateTime.
ZonedDateTime zdt = ZonedDateTime.ofInstant( now , ZoneId.of( "America/Montreal" ) );
First Moment Of The Day
I do not recommend this strategy, but to directly answer your Question about detecting if the time-of-day in a date-time value happens to be the first moment of the day…
First you need to think about time zone. All of these date-time classes mentioned above track time by a count-from-epoch in UTC. The old classes count in milliseconds, the new in nanoseconds. The epoch for both old and new is the first moment of 1970 in UTC. So there is no such thing as a date-time without a time, as you pose it in the Question. The closest thing to that is a date-time whose time-of-day happens to be the first moment of the day. Seems to be your situation (though my discussion above strongly recommends you change your situation).
How to determine if a date-time has a time-of-day that is the first moment of the day? First you must consider time zone. Either you want UTC or you want a particular time zone such as America/Montreal. Depends on your business rules.
If starting with a java.util.Date, first convert to java.time.
Instant instant = myJUDate.toInstant();
Be aware that a date does not always start at the time 00:00:00.0. Because of Daylight Saving Time (DST), and possibly other anomalies, in some places the first moment of the date is a different wall-clock time. The java.time framework can determine this first moment of the day by using the LocalDate class and its atStartOfDay methods.
So after determining the time zone we care about, we adjust our Instant into a ZonedTimeZone.
Instant instant = Instant.now ();
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );
Next we need to see if that is first moment of the day. So we convert to a LocalDate, then back to another ZonedDateTime by calling atStartOfDay. Comparing the first ZonedDateTime to the second tells us if the original was indeed at the start of the day. To sum it up: We are converting from ZonedDateTime → LocalDate → ZonedDateTime.
// Convert to LocalDate, to get start of day, to compare to above.
LocalDate localDate = zdt.toLocalDate ();
ZonedDateTime startOfDay = localDate.atStartOfDay ( zoneId );
Boolean isStartOfDay = ( zdt.isEqual ( startOfDay ) );
Dump to console.
System.out.println ( "instant: " + instant + " for zoneId: " + zoneId + " is zdt: " + zdt + " if compared to startOfDay: " + startOfDay + " is T/F: " + isStartOfDay );
instant: 2015-12-12T23:20:23.560Z for zoneId: America/Montreal is zdt: 2015-12-12T18:20:23.560-05:00[America/Montreal] if compared to startOfDay: 2015-12-12T00:00-05:00[America/Montreal] is T/F: false
If you want UTC rather than a particular time zone, in the code above use the constant ZoneOffset.UTC as your ZoneId object. ZoneOffset is a subclass of ZoneId.
Assuming you're using java.sql.Date which derives from java.util.Date there is no possibility of a Date object not having a time value.
Note the documentation:
http://docs.oracle.com/javase/7/docs/api/java/sql/Date.html
A Date object instance holds a miliseconds value, to be precise the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
Use a Calendar object. The calendar can give you structured access to all fields of a Date value, i.e. year, month, day, hours, minutes, seconds, etc. This would allow you to check whether the time fields are non-zero. As JB Nizet stated, the time part can happen to be zero, in which case wou would misinterpret it as a date only value.

What is the easiest way to get a formatted string from a calendar object which respects timezone?

When I search online about "how to convert a Calendar to a String", all the results I find suggest to first convert to a Date and then convert the Date to a String.
The problem is that a Date is only a representation of the number of milliseconds since the epoch - it does not respect timezone. Calendar is more advanced in this way.
Of course, I could call the individual Calendar.get methods to create my own formatted string, but surely there must be an easier way?
To illustrate, I wrote this code:
long currentTime = Calendar.getInstance().getTimeInMillis();
Calendar calendar = new GregorianCalendar();
calendar.setTimeZone(TimeZone.getTimeZone("Europe/Madrid"));
calendar.setTimeInMillis(currentTime);
System.out.println(calendar.getTime().toString());
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calendar.getTime()));
System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
While running this code from a machine based in London (UTC+0) at 8:02pm, I got the following results:
Wed Nov 18 20:02:26 UTC 2015
2015-11-18 20:02:26
21
The last line shows the real hour according to the calendar's timezone (Madrid which is UTC+1). It is 9:02pm in Madrid, but obviously both the native Date.toString as well as the DateFormat.format methods ignore the timezone because the timezone information is erased when calling Calendar.getTime (similarly Calendar.getTimeInMillis).
Given this, what is the best way to get a formatted string from a Calendar which respects timezone?
Set the timezone on the SimpleDateFormat object and then use z ..
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
sdf.setTimeZone(TimeZone.getTimeZone("Europe/Madrid"));
System.out.println(sdf.format(calendar.getTime());
See here for details on how to handle timezones in Java.
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Europe/Madrid"));
Calendar cal = Calendar.getInstance();
System.out.println(simpleDateFormat.format(cal.getTime()));
java.time
While the other Answers appear to be correct, a better approach is to avoid using java.util.Date/.Calendar entirely.
Those old date-time classes have been superseded by the java.time framework built into Java 8 and later. The new classes are inspired by the highly successful Joda-Time framework, intended as its successor, similar in concept but re-architected. Defined by JSR 310. Extended by the ThreeTen-Extra project. See the Tutorial.
Instant
An Instant represents a moment on the timeline in UTC.
Instant instant = Instant.now ( ); // Current moment in UTC.
For a given Calendar object, convert to an Instant using the method toInstant added in Java 8.
Instant instant = myCalendar.toInstant();
ZonedDateTime
You can assign a time zone (ZoneId) to an Instant to get a ZonedDateTime.
ZoneId zoneId = ZoneId.of ( "Europe/Madrid" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant, zoneId );
String Representation of Date-Time Value
Dump to console.
System.out.println ( "instant: " + instant + " adjusted into zone: " + zoneId + " is zdt: " + zdt );
The java.time classes use ISO 8601 standard formatting by default when parsing/generating String representations of date-time values. By default the ISO 8601 style is extended by appending the name of the time zone in addition to the usual offset-from-UTC.
instant: 2015-11-18T22:23:46.764Z adjusted into zone: Europe/Madrid is zdt: 2015-11-18T23:23:46.764+01:00[Europe/Madrid]
If you want the ISO 8601 style but without the T, either call .replace( "T" , "" ) on the resulting String object or define your own formatter.
The java.time.format package can do the work of determining a localized format appropriate to a particular Locale.
Locale locale = Locale.forLanguageTag ( "es-ES" );
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.FULL );
String output = zdt.format ( formatter.withLocale ( locale ) );
miércoles 18 de noviembre de 2015 23H38' CET
You can use String.format() to avoid timezone problems
http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html
This example gives a result in the format: "yyyy-MM-dd HH:mm:ss"
Calendar c = Calendar.getInstance();
String s = String.format("%1$tY-%1$tm-%1$td:%1$tM:%1$tS", c);
System.out.println(s);
Output:
2015-11-20:44:55

Storing a "fake" timestamp into a database

Here is the problem I am trying to solve: Read a string from database A, convert the string into a Date object, store the Date object into database B.
EX) Database A: Read in date string "2015-03-08 02:00:00" from database A, convert into a Date object, store back into database B.
The problem here occurs because 2:00 AM is the beginning of DST in U.S. Central time, so the Data object converts 2:00 AM straight into 3:00 AM, which means 3:00 AM gets stored into database B.
Is there any way to correct this? I am not opposed to using Joda Time if necessary.
I am trying to focus on the above date, 2015-03-08 02:00:00
This is the code I am using:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = "2015-03-08 02:00:00.0";
try
{
d = sdf.parse(date);
sdf.format(d);
//Insert into database here
// ---
//
}
catch (ParseException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
You have multiple issues intertwined.
You should not be reading strings from a database for date-time values, you should be reading date-time objects. There are many Questions on StackOverflow about reading/writing date-time values from/to databases, so no need to repeat here.
If you do have a string, such as "2015-03-08 02:00:00", notice the lack of any indicator of a time zone or offset. If you want to assume that string represents a time specific the US Central Time, then you must accept the fact that there is no such date-time as that because Daylight Saving Time (DST) defines that as 3 AM. At the stroke of 2 AM, the time labeling jumps to 2 AM. So there is no point in trying to get such a non-existent date-time.
Use Proper Time Zone Names
Big tip for date-time work: Avoid thinking about time zones as "Central Time" and the 3-4 letter codes like "CST". These are not standardized, nor are the unique (many duplicates), and further confuse the mess that is Daylight Saving Time. Use a proper time zone, in pattern of "continent/majorCityOrRegion".
Local Date-Time
Perhaps what you mean is what we call "local time" where the date-time is not specific to any one time zone. For example, "Christmas starts at midnight on December 25th 2015". That means a different moment in each particular time zone. Christmas dawns earlier in Paris, than Montréal, for example.
Joda-Time
Let's interpret that string as a LocalDateTime in Joda-Time. First, for convenience, we replace the SPACE with a "T" to take advantage of Joda-Time’s built-in parsers for ISO 8601 formats.
String input = "2015-03-08 02:00:00";
String inputStandardized = input.replace( " ", "T" ); // For convenience, convert input text to comply with ISO 8601 standard’s canonical format. Replace SPACE between date & time portions with "T".
Next we parse that standardized string.
LocalDateTime localDateTime = LocalDateTime.parse( inputStandardized );
Dump to console.
System.out.println( "inputStandardized: " + inputStandardized );
System.out.println( "localDateTime: " + localDateTime );
When run.
inputStandardized: 2015-03-08T02:00:00
localDateTime: 2015-03-08T02:00:00.000
This local date-time could be stored in a SQL database using the SQL type TIMESTAMP WITHOUT TIME ZONE. This type means no adjustments to UTC time zone are to be made in either getting (SELECT) or putting (INSERT / UPDATE) database values. See Postgres doc for more info on these SQL types.
Zoned Date-Time
If you meant to represent the specific moment in a specific time zone such as America/Chicago, when we need to assign that time zone. For this kind of time-zone-specific values, in your database you would use the data type TIMESTAMP WITH TIME ZONE. That type name is misleading -- it means with respect for time zone, as it adjusts incoming data to UTC. The data's original time zone is then lost.
Unfortunately, this is one of the few situations where Joda-Time lets us down. Rather than do an adjustment, Joda-Time refuses, throwing an exception. ☹
See for yourself… Let's add the following code to the example code above.
DateTimeZone zone = DateTimeZone.forID( "America/Chicago" );
DateTime dateTimeChicago = localDateTime.toDateTime( zone ); // If the input lacks an offset, then Joda-Time *assigns* the value the specified time zone. If the input has an offset, Joda-Time *adjusts* the value to the specified zone.
Dump to console.
System.out.println( "zone: " + zone );
System.out.println( "dateTime: " + dateTimeChicago );
When run.
Exception in thread "main" org.joda.time.IllegalInstantException: Illegal instant due to time zone offset transition (daylight savings time 'gap'): 2015-03-08T02:00:00.000 (America/Chicago
…
There appears to be no good generalized workaround, just hacks. Basically, if you expect a certain time zone, you make the adjustment yourself. See discussions like this, this, this, and the Joda-Time FAQ.
java.time
In Java 8 and later, we have the new built-in date-time framework in the java.time package (Tutorial). This framework was inspired by Joda-Time, and has some advantages over Joda-Time. One of those advantages is handling of this DST non-existent value problem.
String input = "2015-03-08 02:00:00";
String inputStandardized = input.replace( " ", "T" );
LocalDateTime localDateTime = LocalDateTime.parse( inputStandardized );
Let's adjust that local date-time to assign a specific time zone. The java.time framework detects the non-existent date-time and automatically slides the time-of-day forward to respect the DST transition.
ZoneId zone = ZoneId.of( "America/Chicago" );
ZonedDateTime zdt = ZonedDateTime.of( localDateTime, zone );
Dump to console.
System.out.println("inputStandardized: " + inputStandardized );
System.out.println("localDateTime: " + localDateTime );
System.out.println("zone: " + zone );
System.out.println("zdt: " + zdt );
When run.
inputStandardized: 2015-03-08T02:00:00
localDateTime: 2015-03-08T02:00
zone: America/Chicago
zdt: 2015-03-08T03:00-05:00[America/Chicago]
SQL
As said above, you can search StackOveflow for much info on getting date-times in and out of databases.
Ideally, with java.time, you could directly feed either the LocalDateTime or ZonedDateTime to your JDBC driver. But most drivers have not yet be updated to handle the java.time types. Until your driver is updated, fall back on the java.sql.* classes. Convenient conversion methods can be found on both the new and old classes bundled with Java.
java.sql.Timestamp ts = java.sql.Timestamp.valueOf( localDateTime );
…or…
Instant instant = zdt.toInstant();
java.sql.Timestamp ts = java.sql.Timestamp.from( instant );
It's usually better to store the date as milliseconds since epoch. That way, you can use a long to store the number in your database, and when you need to format the date, you can either use Joda Time's DateTime(long) constructor or just the built-in Date(long) constructor.

Java converting string, having millisecond to date object

I have 2 Strings
2012-06-25 15:02:22.948
+0530
I need a new string which adds the 5:30 to the time in the first string.
I thought I can do this by converting both strings to date objects and then adding. But i dont know how to do it, as when i use
yyyy MM dd hh:mm:ss as the date format for the first string, I get an error.
Thanks!
The format of the string 2012-06-25 15:02:22.948 is not yyyy MM dd hh:mm:ss, so it's not surprising that you get "an error" (what error is it? the more specific you are, the better people can help you!).
Try yyyy-MM-dd HH:mm:ss.SSS. See the API documentation of SimpleDateFormat to understand the exact syntax of the format string.
Note: Upper and lower case is important in the format string. hh means 12-hour clock, HH means 24-hour clock. If you use hh, parsing 15 for the hours won't work. You also didn't include the milliseconds SSS in the format string.
You can merge both you string String1+string2 and can use format yyyy-MM-dd HH:mm:ss.SSSZ to parse the date. You can see more documentation here
You're getting an exception because the your date format String is wrong. You're giving a date string on the form
"yyyy-MM-dd hh:mm:ss.S"
See SimpleDateFormat javadoc
Try this:
DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
Date date = format.parse("2012-06-25 15:02:22.948");
Calendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(date.getTime());
int time = Integer.parseInt("0530");
int hour = time / 100;
int minute = time % 100;
calendar.add(Calendar.HOUR_OF_DAY, hour);
calendar.add(Calendar.MINUTE, minute);
String newDateInString = format.format(calendar.getTime());
The other answers are correct but outdated.
java.time
The old date-time classes (java.util.Date/.Calendar etc.) bundled with the earliest versions of Java are now legacy.
Those old classes have been supplanted by the java.time package. See Oracle Tutorial. Much of the functionality has been back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
LocalDateTime
The LocalDateTime class represent a date-time without time zone. Use those for the first piece.
Your format is close to standard ISO 8601 format, just replace the SPACE with a T.
String input = "2012-06-25 15:02:22.948";
String inputStandardized = input.replace( " " , "T" );
LocalDateTime ldt = LocalDateTime.parse( inputStandardized );
Offset from UTC
The other piece is the offset-from-UTC. We use the ZoneOffset class for this.
ZoneOffset offset = ZoneOffset.of( "+0530" );
Without an offset or time zone the LocalDateTime is not an actual moment on the timeline but rather a rough idea about a possible moment. Now we add your offset-from-UTC to mark an actual moment, represented by the OffsetDateTime class.
OffsetDateTime odt = OffsetDateTime.of( ldt , offset );
Zoned
A time zone is an offset plus rules for handling anomalies such as Daylight Saving Time (DST). So better to use a time zone than a mere offset.
For example, if the context of this data is known to be time in India, use a time zone such as Asia/Kolkata to get a ZonedDateTime.
ZoneId zoneId = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = odt.atZoneSameInstant( zoneId );

Categories