0

I have a Date object that is getting the date from the database which is already in UTC, but the timezone offset gets converted based on the location where the application is running.

So if the database has date: 2019-09-06 00:00:00.000 and the application is running in LA, the Date object will have the offset of 7 and the output will look like this 2019-09-06T07:00Z. Since the date is already in UTC, I want it to look like 2019-09-06T00:00Z no matter where it is being run.

The Date class does not have a setTimeZone() method and the first thing that came to mind is to convert it to a String and hardcode 00:00Z at the end, which isn't clean. Any ideas?

More info: The column has a type of DATETIME. DB: SQL Server.

isoplayer
  • 67
  • 2
  • 7
  • 1
    FYI, the terribly troublesome date-time classes such as [`java.util.Date`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/tutorial/datetime/TOC.html) classes built into Java 8 and later. – Basil Bourque Sep 24 '19 at 01:28
  • Specify your database, its version, and the *exact* data type of the column. – Basil Bourque Sep 24 '19 at 02:25
  • Not only is the `Date` class poorly designed and long outdated. Also a `Date` cannot have a time zone. You are asking the impossible. – Ole V.V. Sep 26 '19 at 16:49

2 Answers2

3

I have a Date object that is getting the date from the database which is already in UTC,

Don’t.

The terrible Date class was supplanted years ago by the modern java.time classes.

You should be retrieving a moment from a database column of type TIMESTAMP WITH TIME ZONE by using OffsetDateTime.

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

That value is likely to be in UTC. If you want to view that moment adjusted into a time zone, apply a ZoneId to get a ZonedDateTime.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

but the timezone offset gets converted based on the location where the application is running.

Be aware that while a java.util.Date is actually a moment in UTC, its toString method tells a lie. That method dynamically applies the JVM’s current default time zone while generating its text. While well-intentioned, this anti-feature creates the illusion of a time zone being present inside the Date.

No such problem if you use the java.time classes only. There is no need to ever again use java.util.Date, java.sql.Date, Calendar, GregorianCalendar, SimpleDateFormat, DateFormat, or other such legacy classes.

So if the database has date: 2019-09-06 00:00:00.000 and the application is running in LA, the Date object will have the offset of 7 and the output will look like this 2019-09-06T07:00Z

This part makes no sense to me.

Do you have the correct data types in your database? The TIMESTAMP WITHOUT TIME ZONE would be the wrong type to track a moment. This type has only a date and a time-of-day, but lacks the context of an offset-from-UTC or a time zone. This type cannot represent a specific point on the timeline.

Edit your Question to specify exactly what database and what data types are your columns.

At least try using the java.time to eliminate the confusion of Date::toString injecting an inappropriate time zone.

The Date class does not have a setTimeZone() method

A java.util.Date is always in UTC, just a count of milliseconds since the first moment of 1970 in UTC, 1970-01-01T00:00:00Z. Nothing more. (Actually there is more, a time zone buried deep, with no getter methods, that affects behavior of equals and such, but in irrelevant to our discussion here. This class is a bloody mess of bad design.)

and the first thing that came to mind is to convert it to a String and hardcode 00:00Z at the end, which isn't clean. Any ideas?

No, you definitely should not play such games. You will only get deeper into trouble. Get your data types straight in your database, use only the java.time classes in Java, and your problems will be solved.

I cannot give further help since you did not provide enough details. Search Stack Overflow to learn more. This topic has been addressed many many times already.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1

A Date is a fixed moment in time. It can be displayed using different timezones, but it doesn't itself have a timezone.

A DateFormat, however, like SimpleDateFormat, can be set to use a specific timezone. Set the date format to use TimeZone.getTimeZone("GMT") and you'll get the output you want.

By the way, starting with Java 8, there's a newer, improved date/time API: https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html

kshetline
  • 12,547
  • 4
  • 37
  • 73