Java - Store GMT time - java

My server has GMT+7, so if i move to another server has another GMT timezone, all date stored in db will incorrect?
Yes Q1 is correct, how about i will store date in GMT+0 timezone and display it in custom GMT timezone chosen by each member
How i get date with GMT+0 in java

1) To quote from the javadocs, Java millisecond timestamps are
the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
Therefore, as the timestamp is UTC/GMT, if you store it in the database this date will be correct no matter the time zone of the server.
2) Formatting the timestamp for display depending on the timezone would be the correct approach.
3) Creating a new java.util.Date instance and calling getTime() will get you the timestamp for GMT+0 in Java.

To add to mark's point, once you have a java.util.Date, you can "convert" it to any Timezone (as chosen by the User). Here's a code sample in Groovy (will work in Java with slight mods):
// This is a test to prove that in Java, you can create ONE java.util.Date
// and easily re-display it in different TimeZones
fmtStr = "MM/dd/yyyy hh:mm aa zzz"
myDate = new java.util.Date()
sdf = new java.text.SimpleDateFormat(fmtStr)
// Default TimeZone
println "Date formatted with default TimeZone: " + sdf.format(myDate)
// GMT
sdf.setTimeZone(TimeZone.getTimeZone("GMT"))
println "Date formatted with GMT TimeZone: " + sdf.format(myDate)
// America/New_York
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"))
println "Date formatted with America/New_York TimeZone: " + sdf.format(myDate)
// PST
sdf.setTimeZone(TimeZone.getTimeZone("PST"))
println "Date formatted with PST TimeZone: " + sdf.format(myDate)

By default when you get a date in java its in your current timezone, you can use the TimeZone class to get the timezone your system time is running in. Most databases supports that dates can be stored WITH timezone, which probably would be the right way to do this, but exactly what the format is can be dependant on which database you use.

I would suggest that you use Date only as a "holder" and propose that you use Calendar instances instead. To get a Calendar in the GMT time zone just use this:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+00"))
A Calendar will provide a great deal of benefit when you work with times and dates. For instance, adding an hour to this is simple:
cal.add(Calendar.HOUR, 1);
Lastly, when you need a Date you just use this:
Date date = cal.getTime();

For Q3, consider using ZonedDateTime class.

Related

Set timeZone in Date Java

Trying to set the timeZone in Date( I know Date is deprecated)
LOG.error(modifiedDate + "Date in service"); //Mon Sep 21 06:15:00 CDT 2020
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.ENGLISH);
format.setTimeZone(TimeZone.getDefault());
String dateString = format.format(modifiedDate);
LOG.error(dateString + " dateString"); //2020-09-21 06:15:00 -0500
Date date = format.parse(dateString);
LOG.error(date + " date after parsing"); //Mon Sep 21 06:15:00 CDT
timeZone isn't changing after the parse, what am I missing?
A java.util.Date object is lying. It's not a date. It is a moment in time, and it has no timezone information. It's just a wrapper around millis-since-epoch. It physically doesn't have the neccessary fields to store that.
(let's stop calling an instance of j.u.Date a 'date', because it just isn't one. You might as well call all instances of Integer a 'string', and all files 'a Grandma', about as sane). Let's call them by their right name: "crappy instant".
What you've done is set the timezone of the formatter object. This is working as intended: When you format this crappy instant object with your formatter-with-timezone-info-attached, you get the 'instant in time', translated to human-consumable form, with timezone info, adjusted for that timezone.
Then you ask to parse it back in but that's an issue: that's a very broad job; 'parse this bunch of characters into a "crappy instant"'.
In this case, the bag o' chars you've given includes timezone info already so that will be used. Remember, Date objects are crappy instants - they contain no timezone!!
Which should then raise some eyebrows - as last act you log date, which effectively logs the result of invoking the toString() method on your crappy instant instance. This will.... create a formatter with the system default timezone and use that to render it in human form, but make no mistake, that is NOT actually what is stored in that crappy instant object you have. All that is stored in there is 1600686900000. That's it.
I strongly suggest you follow deHaar's comment: No, you don't want crappy instant. If you have a value handed to you of type crappy instant (java.util.Date), convert it to Instant immediately.
If you must hand off a calculated time value back to some method or interface or field or whatnot and must be in date form, convert your nice instant instance (java.time.Instant) back to a crappy instant form.

Converting Time Zones from a String to UTC (JODA TIME)

I have a stored UTC timestamp in the database. When I retrieve that UTC timestamp I cast it into a String. I want to take that UTC Timestamp String and convert it to the device's local time using Joda Time. Anyone who could possibly help out with this. It would be very appreciated! Here is what I am doing right now:
String date = ""+ds.child("datecreated").getValue();
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
DateTime dt = formatter.parseDateTime(date);
DateTime dt2 = new DateTime(dt).toDateTime(DateTimeZone.getDefault());
String personalDate = dt2.toString();
dateTV.setText(personalDate);
System.out.println("THIS IS THE FIRST TIME: " + dt + "THIS IS THE SECOND TIME: " + dt2);
The problem is is that it is giving me the exact same time when I convert it to my local time, which it shouldn't be doing since it is being stored in UTC and I am converting to Eastern Standard Time which is my phone's default.
To show that Andreas in the comment has hit the nail right on: I ran the following snippet in America/Coral_Harbour time zone (since I didn’t know your exact time zone, Eastern Standard Time is used in several (though fewer after 8 March when Eastern Daylight Time began)).
String date = "2020-03-12T01:23:45.678+0000";
System.out.println("This is the string: " + date);
DateTime dt = new DateTime(date);
DateTime dt2 = new DateTime(dt).toDateTime(DateTimeZone.getDefault());
System.out.println("This is the first time: " + dt);
System.out.println("This is the second time: " + dt2);
Output is:
This is the string: 2020-03-12T01:23:45.678+0000
This is the first time: 2020-03-11T20:23:45.678-05:00
This is the second time: 2020-03-11T20:23:45.678-05:00
Compare the first two lines and notice that the conversion from UTC to EST has already happened when parsing the string.
As an aside, since your string is in ISO 8601 format, you don’t need to specify any formatter for parsing it. The DateTime(Object) constructor accepts it. But the same conversion happened in your parsing.
What happened in your code?
Repeating the quote from Andreas’ comment:
If the withOffsetParsed() has been called, then the resulting
DateTime will have a fixed offset based on the parsed time zone.
Otherwise the resulting DateTime will have the zone of this formatter,
but the parsed zone may have caused the time to be adjusted.
So your formatter has the default time zone of your device, and therefore also the DateTime object that you get from parsing.
So when creating dt2 you were converting from Eastern Standard Time to Eastern Standard Time and therefore got the same date-time again.
Link: Documentation of DateTimeFormatter.parseDateTime()
The part that you are missing is that, as the JavaDoc states, a DateTime object, internally, is represented by the number of "milliseconds from the Java epoch of 1970-01-01T00:00:00Z."
So, a DateTime does not have a time zone. Two DateTime objects that represent the same instant in time are exactly the same, regardless of the time zone represented in the string that you parsed it from.
A DateTime only "has" a timezone when you format it.
When you format it, you get a string with timezone that you requested, and the time representation adjusted accordingly.
The reason that the two dates (dt and d2) look the same to you is because you did not format them (you used their implicit "toString()" methods), so both got formatted with your local time zone.

How to convert String to Date with TimeZone?

I'm trying to convert my String in Date + Timezone.
I get my String from a DateTime Variable (here: xyz).
My code:
String abc = xyz.toString("yyyy-MM-ddZZ");
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-ddXXX");
java.util.Date date = sdf.parse(abc);
System.out.println("Date: " + sdf.format(date));
Error:
Invalid format: "2017-01-03+01:00" is malformed at "+01:00"
If I try SimpleDateFormat("yyyy-MM-dd"); it works but without the Timezone ("+01:00")
The input has a date - year, month, day - and an offset - the difference from UTC - but to build a java.util.Date, you also need the time: hour, minutes, seconds, fraction of seconds.
SimpleDateFormat is terrible because it does some "magic", setting the missing fields to default values. Another problem is that the X pattern doesn't work for all Java versions, and the documentation sucks.
You can use the new Java 8 classes, as explained. With them, you can parse the input, choose the default values to be used for the time fields and convert to java.util.Date, if that's what you need:
DateTimeFormatter fmt = new DateTimeFormatterBuilder().append(DateTimeFormatter.ISO_OFFSET_DATE)
// set hour to midnight
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0).toFormatter();
OffsetDateTime odt = OffsetDateTime.parse("2017-01-03+01:00", fmt); // 2017-01-03T00:00+01:00
The OffsetDateTime will have the time set to midnight, but you can change it to whatever values you need, while with SimpleDateFormat it's not possible, because it uses internal default values and you can't control it.
And the date and offset were correctly set to the values in the input string. You can then convert to java.util.Date if you want:
Date date = Date.from(odt.toInstant());
You can also get the individual "pieces" of the date if you want:
// get just the date
LocalDate localDate = odt.toLocalDate(); // 2017-01-03
// get just the offset
ZoneOffset offset = odt.getOffset(); // +01:00
PS: the offset +01:00 is not the same thing as a timezone. See the difference here
String abc = "2017-01-03+01:00";
TemporalAccessor parsed = DateTimeFormatter.ISO_OFFSET_DATE.parse(abc);
LocalDate date = LocalDate.from(parsed);
ZoneOffset offset = ZoneOffset.from(parsed);
System.out.println("Date: " + date + "; offset: " + offset + '.');
This prints:
Date: 2017-01-03; offset: +01:00.
I am using java.time, the modern Java date and time API, and recommend you do the same. The Date class is long outdated (sorry, no pun intended) and SimpleDateFormat in particular notoriously troublesome. Don’t use them. The modern API is so much nicer to work with. Only if you need a java.util.Date and/or a java.util.TimeZone for a legacy API that you cannot change, convert like this:
Date oldfashionedDate = Date.from(date.atStartOfDay(offset).toInstant());
TimeZone oldfashionedTimeZone = TimeZone.getTimeZone(offset);
System.out.println("Old-fashioned date: " + oldfashionedDate
+ "; old-fashioned time-zone: " + oldfashionedTimeZone.getDisplayName() + '.');
On my computer this prints:
Old-fashioned date: Tue Jan 03 00:00:00 CET 2017; old-fashioned time-zone: GMT+01:00.
I happen to be in a time zone that agrees with your offset from UTC, so it’s fairly obvious that the conversion has given the correct result. In other time zones the output will be more confusing because Date.toString() uses the JVM’s time zone setting for generating the string, but the Date will still be correct.
A date with a time zone? Neither a LocalDate nor a Date can hold a time zone in them, so you need to have the offset information separately. Interestingly your string seems to follow a “ISO-8601-like” format for an offset date that is even represented by a built-in formatter that has ISO in its name. If Java had contained an OffsetDate or a ZonedDate class, I would have expected such a class to parse your string into just one object and even without an explicit formatter. Unfortunately no such class exists, not even in the ThreeTen-Extra project, as far as I can tell at a glance.
Links
Oracle tutorial: Date Time, explaining how to use java.time.
ThreeTen Extra, more classes developed along with java.time.
EDIT: See my updated code run live on ideone.
"2017-01-03+01:00"
I thought it a similar ISO 8601 format date string, but actually not ISO 8601. Thanks #Meno Hochschild and #Basil Bourque's indication.
It is so luck that this method works for such format's string: javax.xml.bind.DatatypeConverter.parseDateTime, it will return a Calendar:
System.out.println(DatatypeConverter.parseDate("2017-01-03+01:00").getTime());
Output:
Tue Jan 03 07:00:00 CST 2017
From the method javadoc:
public static Calendar parseDate(String lexicalXSDDate)
Converts the string argument into a Calendar value.
Parameters: lexicalXSDDate - A string containing lexical
representation of xsd:Date.
Returns: A Calendar value represented by
the string argument.
Throws: IllegalArgumentException - if string
parameter does not conform to lexical value space defined in XML
Schema Part 2: Datatypes for xsd:Date.

Convert UTC to LocalDateTime in Joda?

DateTime dt = new DateTime("2014-09-15T21:20:14");
System.out.println(dt);
System.out.println(dt.plusMillis(581042272).toDateTime().toLocalDateTime().toDateTime(DateTimeZone.forID("GMT")));
the time in dt is in UTC, I want to set the time in dt plus milliseconds to GMT? However, the time is still printed as UTC (1 hour behind GMT). How can I set it so it's one hour in front?
2014-09-15T21:20:14.000+01:00
2014-09-22T14:44:16.272Z
I know the time is exactly one hour behind because I made this request at 15:44:16 GMT
Your DateTime is actually not in UTC - it's in the system default time zone. To fix it, you just need to tell it that the value you're passing in is in UTC:
DateTime dt = new DateTime("2014-09-15T21:20:14", DateTimeZone.UTC);
System.out.println(dt);
DateTime other = dt.plusMillis(581042272);
System.out.println(other);
Output:
2014-09-15T21:20:14.000Z
2014-09-22T14:44:16.272Z
Also note that you can't have made the request at 15:44:16 GMT, as that hasn't occurred yet. At the time I'm writing this, it's 16:05 British Summer Time, therefore 15:05 GMT. It's important to understand that the time zone in the UK isn't "GMT" - that's just the part of the time zone when we're not observing daylight savings.
If you want to convert to the UK time zone, you want:
DateTime other = dt.plusMillis(581042272)
.withZone(DateTimeZone.forID("Europe/London"));
For those that have trouble with converting datetime from a server to local datetime:
1.Make sure the server gives you a UTC time, meaning, the format should contain a timezone.
2.Convert with pattern, if the api does not give you an timezone, then you might get an exception because of the last 'Z'.
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
DateTime dt = formatter.parseDateTime(currentPost.postDate);
3.to check the time offset (optional)
DateTimeZone ActualZone = dt.getZone();
4.Convert to local time
TimeZone tz2 = TimeZone.getDefault();
DateTime localdt = new DateTime(dt, DateTimeZone.forID(tz2.getID()));
(if you control the API yourself, and it happens to be an asp.net api, check this, to set the Kind of the datetime, even though you might have saved it as UTC time in the database, you will send the datetime with the default server timezone)
val marketCentreTime = timeInAnotherTimezone.withZone(DateTimeZone.forID("yourCountryName/andyourCityName"));

Is it possible to create a Calendar object like Tue Mar 03 13:43:00 (without time zone)?

I have a requirement of sending the calendar object with time zone, like Tue Mar 03 13:43:00. I know that Calendar object always return with Tue Mar 03 13:43:00 CST 2009, so how can I create it without the time zone?
You can use the DateFormat class (more specifically the SimpleDateFormat concrete subclass) to format the date however you want. Here is an example:
Calendar cal = Calendar.getInstance();
DateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss");
String dateString = format.format(cal.getTime()));
Prints:
Fri Mar 06 15:50:26
It's not possible to have a Calendar object without a TimeZone. Really, that doesn't make any sense - Calendar seeks to represent "a specific instant in time" - how can you represent an instance in time without knowing what TimeZone the time you are representing is in?
So, there's a few things to consider:
You say you need to pass this Calendar to some other component - does that API care what TimeZone the Calendars are in? Will that API ignore the TimeZone setting, use it to calculate a time difference against it's own local timezone, etc.?
Are you aware that you can easily change the TimeZone of a Calendar instance?
Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getDefault()); // returns default TimeZone for your system
cal.setTimeZone(TimeZone.getTimeZone("EST")); // Eastern Standard Time
cal.setTimeZone(TimeZone.getTimeZone("Asia/Kolkota"); // UTC+5:30
Javadocs on Calendar, TimeZone.
You can use a simple Date object using;
Date d = new Date();
Date d2 = calendar.getTime();
Or the even simpler, time in milli-seconds.
long time = System.currentTimeMillis();
To avoid confusion over time zones, I suggest storing and setting all date/times as a standard time zone, such as GMT+0 and then converting the time for display etc as required.
Upon rereading your question and your comments on my other answer, it sounds like the problem is that you want the result to be a Calendar object, not a String. So it isn't a question of formatting the String representation of the Calendar.
In this case, what you are asking is technically impossible: all implementations of the Calendar class exist to represent an internal time, which is stored as the number of milliseconds since the Unix epoch (Jan 1 1970 00:00 GMT). The time "5:00 am" in Boston is different from "5:00 am" in Seattle--they have different internal timestamps.
Your best bet would be to use the same time zone everywhere, and probably GMT makes the most sense for that purpose:
cal.setTimeZone(TimeZone.getTimeZone("GMT+0000"));

Categories