Convert UTC millisecond to UTC date in java - date

I am working in application where facing issue with time zones.
Want to convert UTC millisecond to UTC date object.
I already tried
TimeZone utcZone = TimeZone.getTimeZone("UTC");
Calendar date = getInstance(utcZone);
date.setTimeInMillis(utcMillisecond);
date.getTime();
date.getTime is still returning my local time zone that is EST. I know that millisecond that I am getting from UI is in UTC millisecond.

The old class java.util.Calendar silently applied your JVM’s current default time zone. You assumed it would be in UTC but it is not.
java.time
You are using old troublesome date-time classes that have been supplanted by the java.time framework in Java 8 and later.
I assume that by "UTC millisecond" you mean a count of milliseconds since the first moment of 1970 in UTC, 1970-01-01T00:00:00Z. That can be used directly to create a java.time.Instant, a moment on the timeline in UTC.
By the way be aware that java.time has nanosecond resolution, much finer than milliseconds.
Instant instant = Instant.ofEpochMilli( yourMillisNumber );
Call toString to generate a String as a textual representation of the date-time value in a format compliant with the ISO 8601 standard. For example:
2016-01-23T12:34:56.789Z

Related

Dart DateTime.parse timeZoneOffset is always 0

The DateTime created by DateTime.parse seems to always returns 0 for "timeZoneOffset"
I create a ISO8601 string here in a non UTC timezone: https://timestampgenerator.com/1610010318/+09:00
I pass that string to DateTime.parse:
DateTime date = DateTime.parse("2021-01-07T18:05:18+0900");
Issue: timeZoneOffset is 0 when I was expecting +0900.
print(date.timeZoneOffset); --> 0:00:00.000000
print(date.timeZoneName); --> UTC
print(date); --> 2021-01-07 09:05:18.000Z
Dart DateTime documentation (https://api.dart.dev/stable/2.10.4/dart-core/DateTime/parse.html):
The result is always in either local time or UTC. If a time zone offset other than UTC is specified, the time is converted to the equivalent UTC time.
Why is timeZoneOffset 0? What string do I need to pass to DateTime.parse to get it to store the time in local time instead of converting it to the equivalent UTC time?
The Dart SDK does not really handle different timezones which is the reason why the parse want local timezone (which is the timezone on the system running the program) or UTC.
If you are trying to parse a timestamp without any timezone information, Dart will assume the time are in local timezone (I am in Denmark which are using the Romance Standard Timezone):
void main() {
print(DateTime.parse("2021-01-07T18:05:18").timeZoneName); // Romance Standard Time
print(DateTime.parse("2021-01-07T18:05:18+0900").timeZoneName); // UTC
}
You can convert your UTC timestamp into localtime by using .toLocal() on the timestamp. But again, this will just convert it into the timezone which are on your own system and not the one coming from the time you have parsed:
void main() {
print(DateTime.parse("2021-01-07T18:05:18+0900").toLocal().timeZoneName); // Romance Standard Time
}
If you want to handle time with timezone data you should look into the package timezone: https://pub.dev/packages/timezone
Some notes about saving timezone offset
You should be aware that in most cases, it does not really makes sense to save the time in a form where you can get the original offset again. The problem is that most countries have rules like DST or the user are traveling and does expect the system to handle the time correctly.
So in a lot of cases, the user does not really expect to get the same offset back again but want the time to be with the currently offset based on location and time right now.
The timezone package does e.g. not allow you to parse a timestamp and save the offset together with it (because an offset is not the same as a location). Instead, it want you to specify the location the timestamp are used for so it can calculate the current offset for that location.
So in general, I recommend you to always save time as UTC on storage. When the data are going to be used, you should have some way to know the location of the receiver (e.g. ask the user in some form of profile) and convert the time to that location using the timezone package. If the application are running on a device owned by the receiver of the data, you can convert the UTC to local time using .toLocale().

Is it possible to specify an ISO Date with a timezone (i.e. GMT offset) but without a time?

I'm trying to see if you can specify a date with a timezone in ISO but without also specifying a time.
This may seem odd to ask about having a timezone without actually having a time, but technically a date represents a range between two times... the 24-hour period spanning from midnight to midnight, and that 'midnight' has to be in a timezone.
In our case, we have an API that wants to say 'Filter things on-or-before date X and on-or-after date Y' and we want the user to specify 'April 9th' (in their time zone) for both to get all things that happen on that day.
Of course we solve this by adding a day to the first date, then changing it to a pure 'before', but the front-end is required to do that math. We can't do it on the backend because having to send a date with a time means we would be sending April 9th at midnight, then on the backend adding a day to that, but what if someone passed in 4pm?
We could fail the date if it has a non-midnight time, but then we're back to why pass it in the first place.
So again, can you have a date with a timezone but not have a time component?
To decode ISO8601 dates only with year-month-day and time zone set the appropriate formatOptions of the ISO8601DateFormatter
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withFullDate, .withTimeZone]
If by time zone you mean a UTC offset (as used with ISO 8601 dates with times), this is no problem. If by time zone you mean a true time zone with historic, present and known future offsets from UTC, including for example summer time/DST, like America/New_York or North American Eastern Time, then ISO 8601 does not support that, neither for dates with nor without time of day.
2020-04-25-04:00
This is perfectly valid ISO 8601 for April 25 this year at offset -04:00. So you may use it for representing the interval from 2020-04-25T00:00-04:00 (inclusive) to 2020-04-26T00:00-04:00 (exclusive). Which would then be equivalent to 2020-04-25T04:00Z to 2020-04-26T04:00Z (Z meaning UTC).
Java example code
I don’t know any Swift, so cannot tell you how to format or parse such a string in Swift. In Java formatting it is not bad. Example:
LocalDate date = LocalDate.of(2020, Month.APRIL, 25);
String isoOffsetDateString = date
.atStartOfDay(ZoneId.of("America/New_York"))
.format(DateTimeFormatter.ISO_OFFSET_DATE);
System.out.println(isoOffsetDateString);
Output:
2020-04-25-04:00
I am using Java’s built-in ISO_OFFSET_DATE formatter. The documentation informs us that this formnatter is:
The ISO date formatter that formats or parses a date with an offset,
such as '2011-12-03+01:00'.
Parsing the string and producing the start and end of the day takes a little more:
TemporalAccessor parsed
= DateTimeFormatter.ISO_OFFSET_DATE.parse(isoOffsetDateString);
Instant start = LocalDate.from(parsed)
.atStartOfDay(ZoneOffset.from(parsed))
.toInstant();
Instant end = start.plus(1, ChronoUnit.DAYS);
System.out.println("From " + start + " inclusive to " + end + " exclusive");
From 2020-04-25T04:00:00Z inclusive to 2020-04-26T04:00:00Z exclusive
I have opted to convert to Instant, the class for a moment in time independent of offset or time zone. Instants print in UTC, as the trailing Z on each says. In your Java code you may prefer not to do this conversion or to do a different conversion, all depending on circumstances.
Link
Documentation of DateTimeFormatter.ISO_OFFSET_DATE

What is the standard for encoding a date as a timestamp?

Is there a standard for encoding a date as a timestamp? My thoughts:
This should be 12:00pm UTC in local time, eg 9:00am at T-3, therefore anyone consuming the timestamp, regardless of their -12/+12 offset, will recognize the same date, regardless of whether they parse at the UTC timezone
It could be 12:00pm at UTC
It could be the start of the day (12:00am) at UTC
It could be start of the day (12:00am UTC) in local time eg 9:00pm at T-3
Is there an official spec or standard to adhere to?
It would be easy to point to this document and say 'this is the standard' as opposed to being unaware and having to change our logic down the line.
There isn't a standard for this, because a date and a timestamp are logically two very different concepts.
A date covers the entire range of time on that day, not a specific point in time.
It may be a different date for a person in another time zone at any given point in time, but dates themselves do not have any association with time zones. Visualize a date as just a square on a calendar, not a point on a timeline.
Many APIs will use midnight (00:00) as the default time when a date-only value is assigned to a date+time value. However:
Whether it is UTC based or local-time based is very dependent on that particular API. There is no standard for this, nor is one answer necessarily better than the other.
Assigning a local-time midnight can be problematic for time zones with transitions near midnight. For example, in Santiago, Chile on 2019-09-08, the day started at 01:00 due to the start of DST. There was no 00:00 on that day.
Also, you tagged your question with momentjs. Since a Moment object is basically a timestamp (not a date), then Moment.js will generally assign the start of the day if provided a date-only value. The time zone involved is key to deciding which moment that actually is, which illustrates my prior points.
For example:
// Parsing as UTC
moment.utc('2019-09-08').format() //=> "2019-09-08T00:00:00Z"
// Parsing as Local Time (my local time zone is US Pacific Time)
moment('2019-09-08').format() //=> "2019-09-08T00:00:00-07:00"
// Parsing in a specific time zone (on a day without midnight)
moment.tz('2019-09-08', 'America/Santiago').format() //=> "2019-09-08T01:00:00-03:00"
Also keep in mind that sometimes APIs can be misnamed. The JavaScript Date object is not a date-only value, but actually a timestamp, just like a moment.

need to convert UTC time to current timezone of device

Im using this repo
https://github.com/remirobert/Tempo
Can someone help me understand how to grab the current time zone of the device, and then notify tempo? I am using the timeAgoNow() function of tempo to find display how long ago the post was made, but the timezone difference is messing it up. My datasource is using UTC time.
Cocoa uses UTC internally. for all of its date/time calculations.
If you create an NSDate for now:
NSDate()
You get a date that is the number of elapsed seconds since midnight, 1970 in UTC time.
Dates only have time zones when you display them.
By default logging a date to the console logs it in UTC, which can be confusing.
If I'm working on a project that does a lot of date/time calculations I'll create a debugging method that converts an NSDate to a date/time string in the current locale, which is easier to read/debug without having to mentally convert from UTC back to local time.
I have never used Tempo, so I don't know if it is using date strings, NSDate, or "internet dates" (which are also in UTC, but use a different "zero date" or "epoch date")

DST problems with storing Joda LocalDateTime in a PostgreSQL 'timestamp' column

In our app we're storing datetimes that belong to many different timezones.
We decided to use the Joda LocalDateTime type - so that the user always gets literally whatever they entered in the first place. This is exactly what we need.
Internally we know which timezone the user belongs to - so when they enter a datetime we do a check like this:
dateTimeZone.isLocalDateTimeGap(localDateTime)
If that datetime does not exist in their timezone (it's in the daylight-savings gap) we display an error message that the date is not correct, thus preventing incorrect datetimes from being stored in the DB.
For storing we're using a timestamp column. Problems start when the user-entered datetime exists in their timezone but does not exist in the database timezone (Europe/Berlin). E.g. when I store LocalDateTime 2015-03-29 02:30:00 from the Europe/London timezone (this is valid - in London the gap is between 01:00 and 02:00), PostgreSQL shifts the hour by 1 and saves it as 2015-03-29 03:30:00.
What to do? Is there a way to tell PostgreSQL not do anything regarding timezones and just store datetimes literally as Joda represents them? (other than storing them as strings ;))
In PostgreSQL 7.3 and higher, timestamp is equivalent to timestamp without time zone. That data type is not time zone aware. It stores only a date and time. If you are finding it shifted, then it might be related to the code or tools you are using to store or retrieve the data.
Note that before version 7.3, timestamp was equivalent to timestamp with timezone. This is mentioned in the first note-box in the documentation here.
Postgres offers two date-time types per the SQL standard. The standard barely touches on the topic unfortunately, so the behavior described here is specific to Postgres. Other databases may behave differently.
TIMESTAMP WITHOUT TIME ZONEStores just a date and a time-of-day. Any time zone or offset-from-UTC passed is ignored.
TIMESTAMP WITH TIME ZONEFirst adjusts the passed date+time using its passed zone/offset to get a value in UTC. The passed zone/offset is then discarded after the adjustment is made; if needed, you must store that original zone/offset information in a separate column yourself.
Be aware that TIMESTAMP WITHOUT TIME ZONE does not represent an actual moment, does not store a point on the timeline. Without the context of a zone or offset, it has no real meaning. It represents a range of possible moments over a span of about 26-27 hours. Good for problems such as storing a appointment far enough out in the future that the time zone rules may be changed before its arrival. Also good for problems such as “Christmas starts after midnight on December 25 this year”, where you mean a different moment in time in each zone with each zone westward arriving later and later in succession.
When recording actual moments, specific points on the timeline, use TIMESTAMP WITH TIME ZONE.
The modern approach in Java uses the java.time classes rather than either the Joda-Time library or the troublesome old legacy date-time classes bundled with the earliest versions of Java.
TIMESTAMP WITHOUT TIME ZONE
For TIMESTAMP WITHOUT TIME ZONE, the equivalent class in java.time is LocalDateTime for a date and time-of-day without any offset or zone.
As others pointed out, some tools may dynamically apply a time zone to the retrieved value in a misguided and confusing albeit well-intentioned anti-feature. The following Java code will retrieve your true date-time value sans zone/offset.
Requires a JDBC driver compliant with JDBC 4.2 or later to directly work with java.time types.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ; // Retrieving a `TIMESTAMP WITHOUT TIME ZONE` value.
To insert/update database:
myPreparedStatement.setObject( … , ldt ) ; // Inserting/updating a `TIMESTAMP WITHOUT TIME ZONE` column.
TIMESTAMP WITH TIME ZONE
Your discussion of time zones suggests you are concerned with actual moments on the timeline. So you should absolutely be using TIMESTAMP WITH TIME ZONE instead of TIMESTAMP WITHOUT TIME ZONE. You should not be messing about with Daylight Saving Time (DST) gaps and such. Let java.time and Postgres do that work for you, with much better code already written and tested.
To retrieve:
Instant instant = myResultSet.getObject( … , Instant.class ) ; // Retrieving a `TIMESTAMP WITH TIME ZONE` value in UTC.
ZonedDateTime zdt = instant.atZone( ZoneId.of( "Africa/Tunis" ) ) ; // Adjusting from a UTC value to a specific time zone.
To insert/update database:
myPreparedStatement.setObject( … , zdt ) ; // Inserting/updating a `TIMESTAMP WITH TIME ZONE` column.
To retrieve from database:
Instant instant = myResultSet.getObject( … , Instant.class ) ;
E.g. when I store LocalDateTime 2015-03-29 02:30:00 from the Europe/London timezone
No, no, no. Do not work this way. You are misusing the types of both Java and Postgres.
If the user entered 2015-03-29 02:30:00 intended to represent a moment in Europe/London time zone, then parse as a LocalDateTime and immediately apply a ZoneId to get a ZonedDateTime.
To parse, replace the SPACE in the middle with a T to comply with ISO 8601 standard formatting used by default in the java.time classes.
String input = "2015-03-29 02:30:00".replace( " " , "T" ) ;
LocalDateTime ldt = LocalDateTime.parse( input ) ;
ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
To see that same moment in UTC, extract a Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instant = zdt.toInstant() ;
Pass the instant via JDBC for storage in the database in a TIMESTAMP WITH TIME ZONE.
myPreparedStatement.setObject( … , instant ) ;
Use objects, not strings
Note that all my code here is using java.time objects to exchange data with the database. Always use these objects rather than mere strings for exchanging date-time values.
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, 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
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
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.