Date difference includes Timezone offset, what's wrong? - java

I have this code:
Date now = new Date();
// the string is in UTC format, so a UTC date must be constructed, I don't know if that happens in this format
Date measure = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(utcDateTime);
long diff = now.getTime() - measure.getTime();
if (diff < 1000* 60 * 15) {
// measure is less then 15 minutes recent
do some work
}
When I get the diff, it includes the timezone. I know the Date object internally is UTC.
So what's wrong here?

While a Date object is indeed in UTC, your SimpleDateFormat may not be. I suspect it default's to the system time zone - that's certainly what experimentation would suggest. You can change this using DateFormat.setTimeZone. So if your text represents a UTC date/time, you should set the time zone of the formatter to UTC as well.
Or you could use Joda Time, which is a generally better date and time API :)

Related

How to convert UTC timezone to localtime zone using Joda-Time in Java? [duplicate]

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"));

How to parse offset it is not specified?

I have time 12:00:00 in format HH:mm:ss.
I know that this time comes from server witch is setup with +3 offset.
If i use SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");, it parses time with regard to device, which can be in a different timezone.
Is there another way to parse it with regard to +3 offset except adding it to the original string?
First, should your server rather send the time in UTC? If clients are everywhere, this would seem more time zone neutral and standardized. However, the way to handle it in code wouldn’t be much different. In any case the server offset form UTC could be constant:
private static final ZoneOffset serverOffset = ZoneOffset.ofHours(3);
In real code you will probably want to make it configurable somehow, though. To parse:
OffsetTime serverTime = LocalTime.parse("12:00:00").atOffset(serverOffset);
System.out.println(serverTime);
This prints
12:00+03:00
Since your time format agrees with LocalTime’s default (ISO 8601), we need no explicit formatter. If a representation of the time with offset is all you need, we’re done. If you need to convert to the user’s local time, to do that reliably you need to decide both a time zone and a date:
LocalTime clientTime = serverTime.atDate(LocalDate.of(2018, Month.JANUARY, 25))
.atZoneSameInstant(ZoneId.of("Indian/Maldives"))
.toLocalTime();
System.out.println(clientTime);
With the chosen day and zone we get
14:00
Please substitute your desired time zone and date.
Just hypothetically, if you knew the user’s offset from UTC, you could use just that:
LocalTime clientTime = serverTime.withOffsetSameInstant(ZoneOffset.of("-08:45"))
.toLocalTime();
The example yields 00:15. However, no one knows when the politicians introduce summer time (DST) or other anomalies in the user’s time zone, so I discourage relying on an offset alone.
And yes, I too am using java.time. SimpleDateFormat is not only long outdated, it is also notoriously troublesome, so java.time is what I warmly recommend.
Set the timezone on your SimpleDateFormat object:
SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT+03:00"));
I recommend you use the Java 8 date and time API (package java.time) instead of the old API, of which SimpleDateFormat is a part.
Using the Java 8 DateTime API:
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("HH:mm:ss");
LocalTime clientLocalTime = LocalTime
.parse("12:00:00", formatter)
// Create an OffsetTime object set to the server's +3 offset zone
.atOffset(ZoneOffset.ofHours(3))
// Convert the time from the server timezone to the client's local timezone.
// This expects the time value to be from the same day,
// otherwise the local timezone offset may be incorrect.
.withOffsetSameInstant(ZoneId.systemDefault().getRules().getOffset(Instant.now()))
// Drop the timezone info - not necessary
.toLocalTime();

java Date conversion confusion regarding timezones

I'm using Java 6. Our servers are on Eastern Standard Time (GMT-5), and I'm trying to store a value that should be interpreted as such but I'm confused about how to convert it. I have
String dateStr = "1368921600000"; // This is 5/19/2013 00:00:00
final Calendar cal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone("GMT-5"));
cal.setTimeInMillis(Long.parseLong(dateStr));
final java.util.Date dateObj = cal.getTime();
System.out.println(dateObj.toString());
but right now this prints out "Sat May 18 19:00:00 CDT 2013" (since my local machine is on CDT) but I want the result to be "Sat May 18 24:00:00 CDT 2013". How can i interpret the date string "1368921600000" as an EST date? Thanks, - Dave
1368921600000 is an instant in time, the same instant, everywhere in the world. To convert this to a date and time, you have to specify where in the world you want to know the date/time at that instant. It just so happens that the timestamp is relative to UTC, and is Sun, 19 May 2013 00:00:00 GMT.
If you want the time of this instant (the same instant) somewhere else in the world, you can use the Calendar as you did and extract the individual field values (e.g. HOUR_OF_DAY). If all you care about is getting a text string, you use a DateFormat instance such as SimpleDateFormat:
DateFormat df = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z");
df.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String timeOnUSEastCoast = df.format(new Date(1368921600000L));
// will be GMT-5 or GMT-4 depending on DST
In this example, the output would be GMT-4: Sat, 18 May 2013 20:00:00 EDT (not only has the hour changed, but it's still the previous day on the US east coast).
If you want to output the UTC time but just want to pretend it's EST then it's just easier to tell the DateFormat to leave off the time zone field (remove the "z") in the text output and call it whatever you want, but understand that the timestamp value is always UTC.
It is often not necessary to use the Joda Time library to get historically accurate time-zone- and daylight-savings-aware local time mappings, although this is the common go to response for many.
If you have a database of timestamps that require local time conversion, then here are some principles that have served me well:
Store date/times (Instants, in the parlance of Joda; Dates, in the parlance of the Java Calendar API) in UTC time. UTC does not care about DST. It does not care about time zones. UTC simply represents a universally representable moment in time. This step alone can save a lot of date/time headaches.
Database records should contain TimeZone and/or Locale fields so that mapping from UTC can be performed. Think about your data. Every timestamp in your database does not need time zone information associated with it. Instead, associate the time zone data with a part of your data model that provides appropriate granularity. If your app will only ever be localized in one time zone, then you needn't store this infor at all. In my recent project, I created a Locale table that contains the TZ ID for timestamps in my Encounters table. All other timestamps are subordinate to these records, so it made sense to associate it there.
Use the Java API GregorianCalendar to map UTC Dates to local time. And that's all I ever use it for. I almost never use GregorianCalendars to do date arithmetic or other date operations. Here is the paradigm that I've been working with:
public static void main(String[] args) {
m_GregorianCalendar = new GregorianCalendar(TimeZone.getTimeZone(
"America/Chicago"));
Date d = new Date();
String fmt = "dd-MMM-yyyy # HH:mm";
:
:
String myDate = mapToLocalTime(d, fmt, gc);
:
:
}
public String mapToLocalTime(Date utc, String format, GregorianCalendar gc) {
gc.setTime(utc); // this calendar is already timezone aware (constructed
// with time zone id (DST too))
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.setCalendar(gc); // formatter uses conventions of calendar
sdf.applyPattern(fmt); // pattern for formatter
return sdf.format(utc);
}
Consider representing timestamps internally in a numeric format (longs, doubles). This greatly simplifies date comparisons and date arithmetic. The only downside is that conversions must be done to format the data into a human recognizable form, but if you use functions for these conversions it need not be a big deal at all.
Use either a new java.util.SimpleDateFormat(format) or java.util.DateFormat.getDateTimeInstance(int,int), then use #setTimeZone(timezone).
When you're printing Date.toString(), the Calendar's time zone is not taken into consideration at all. After you do a cal.getTime(), whatever was set in Calendar is no longer relevant.
What is is TimeZone's default time zone.
So right before printing the date, set the default time zone to the one you want to print in, e.g.:
String dateStr = "1368921600000"; // This is 5/19/2013 00:00:00
final Calendar cal = Calendar.getInstance();
TimeZone gmtZero = TimeZone.getTimeZone("GMT");
cal.setTimeInMillis(Long.parseLong(dateStr));
final java.util.Date dateObj = cal.getTime();
TimeZone.setDefault(gmtZero);
System.out.println(dateObj.toString());
This will print the date in GMT regardless of your system time zone.
Just remember to bring back the original default TimeZone afterwards!

Java How to create a UTC and add few ms to the same UTC object

static String createUTCTime()
{
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
cal.add(Calendar.SECOND, 10);
SimpleDateFormat f = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
f.setCalendar(cal);
return f.format(new Date());
}
essentially what I would like to do below
Calendar objectX = createUTCTime();
//2012-Nov-27 18:35:40
x.addMS(10);
//2012-Nov-27 18:35:50
How do you handle UTC times to manipulate them?
Date is just a point in time, it doesn't hold any time zone information. If you want to work with time zones and dates, you need Calendar:
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
cal.add(Calendar.SECONDS, 10);
Now the tricky part, you cannot just convert it to Date (cal.getTime()) as it will loose time zone (but will still represent the same point-in-time). What you should do is create a SimpleDateFormat` configured to use UTC.
On the other hand if you only need seconds or milliseconds, Date is fine. Just remember to format it in correct time zone. But you shouldn't use Date for hours and everything above (assumption that hour is 3600000 milliseconds is sometimes wrong due to leap seconds, DST, etc.)
It's really unclear what you're trying to do - but if you're trying to create an object to work with further, you shouldn't be converting it into a string representation, which is what SimpleDateFormat.format does.
The Java API for working with dates and times is pretty broken, to be honest - you'd be much better off with Joda Time. For example:
DateTime x = new DateTime(DateTimeZone.UTC);
x = x.plusMillis(10);
Joda Time provides plenty of immutable types for dates and times, which are significantly better for readability than the mutable Calendar and Date types. Additionally, it supports a lot more types to represent different kinds of values.
Really, avoid java.util.Date/Calendar like the plague :)
You can use following code.
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.add(Calendar.MILLISECOND, 10);
DateFormat df = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
SimpleDateFormat f = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
f.setTimeZone(cal.getTimeZone());
System.out.println(f.format(cal.getTime()));
getTime provide Date object which do not have any information about timeZone. By Date object can display the date in GMT(toGMTString()) and local time zone(toLocalString()).
This code will provide you time in UTC, in the required format.

Get Time in London

How can I get the current local wall clock time (in number of millis since 1 Jan 1970) in London? Since my application can run on a server in any location, I think I need to use a TimeZone of "Europe/London". I also need to take Daylight Savings into account i.e. the application should add an hour during the "summer".
I would prefer to use the standard java.util libraries.
Is this correct?
TimeZone tz = TimeZone.getTimeZone("Europe/London") ;
Calendar cal = Calendar.getInstance(tz);
return cal.getTime().getTime() + tz.getDSTSavings();
Thanks
I'm not sure what this quantity represents, since the "number of millis since 1 Jan 1970" doesn't vary based on location or daylight saving. But, perhaps this calculation is useful to you:
TimeZone london = TimeZone.getTimeZone("Europe/London");
long now = System.currentTimeMillis();
return now + london.getOffset(now);
Most applications are better served using either UTC time or local time; this is really neither. You can get the UTC time and time in a particular zone like this:
Instant now = Instant.now(); /* UTC time */
ZonedDateTime local = now.atZone(ZoneId.of("Europe/London"));
Others have said that it may well not be a good idea to do this - I believe it depends on your situation, but using UTC is certainly something to consider.
However, I think you've missed something here: the number of seconds which have occurred since January 1st 1970 UTC (which is how the Unix epoch is always defined - and is actually the same as in London, as the offset on that date was 0) is obtainable with any of these expressions:
System.currentTimeMillis()
new Date().getTime()
Calendar.getInstance().getTime().getTime()
If you think about it, the number of milliseconds since that particular instant doesn't change depending on which time zone you're in.
Oh, and the normal suggestion - for a much better date and time API, see Joda Time.
To get the current time in London:
SimpleDateFormat f = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
f.setTimeZone(TimeZone.getTimeZone("Europe/London"));
System.out.println(f.format(GregorianCalendar.getInstance().getTime()));

Categories

Resources