I want to subtract a few days from my timestamp in Android.
I have an SQLite database with a date field of the type long.
When I execute a query where I say date = date - (3 * 86400000) I sometimes experience a one hour difference as a result when converting it to a readable date.
But how is this possible? Has it to do with the daylight savings of one hour in my timezone?
Because I would find it strange if that's the reason because you are doing calculations with two long values and after converting them back to datetime there shouldn't be a daylight saving issue?
Thanks for the replies but I found a solution.
It seems that when you add days in milliseconds to your timestamp and there is an hour difference in daylight settings in between, the date is automatically corrected.
When I do the following, the hour is ignored:
Date d = new Date();
d.setDays(d.getDays() - 2);
However, I would recommend using the Joda library because it's mush more flexible and easy to work with.
tl;dr
Use modern java.time classes.
If you meant 3 days as in calendar dates, do this:
Instant // Represent a moment in UTC with a resolution of nanoseconds.
.ofEpochSecond( x ) // Parse some number of whole seconds or milliseconds from the epoch reference of first moment of 1970 in UTC.
.atZone( // Adjust from UTC to the wall-clock time used by the people of a particular region (a time zone).
ZoneId.of( "Pacific/Auckland" ) // Assign the time zone by which you want the context of their calendar for adding dates.
) // Returns a `ZonedDateTime` object.
.plus( // Move to another moment by adding a span-of-time.
Period.ofDays( 3 ) // Define a span of time as a number of days on the calendar (date) without regard for the length of a day.
) // Returns another `ZonedDateTime` object.
.toInstant() // Adjust from a time zone to UTC. Same moment, different wall-clock time.
.toEpochSeconds() // or maybe `toEpochMillis` depending on your practice with your `long` number.
Write your SQL as:
SELECT * FROM event_ WHERE when_ >= ? ; -- Find events occurring later than the passed moment.
In Java with JDBC 4.2 or later:
myPreparedStatement.setObject( 1 , secondsSinceEpoch ) ; // Pass seconds calculated above.
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Count-from-epoch
Your number of type long is presumably a count of whole seconds or milliseconds since an epoch reference date.
If your chosen epoch happens to be that used by “Unix time”, the first moment of 1970 in UTC, 1970-01-01T00:00:00Z, then we can parse in Java as an Instant. An Instant is a moment on the timeline in UTC with a resolution of nanoseconds. An Instant internally is a pair of numbers: a count of whole seconds since epoch, plus a fraction of a second as a count of nanoseconds.
Instant instant = Instant.ofEpochMilli( x ) ;
…or:
Instant instant = Instant.ofEpochSecond( x ) ;
A day is not 24 hours
A day, as in a date on the calendar, is not the same thing as 24 hours. Anomalies in the way politicians define time zones such as Daylight Saving Time (DST) means a day might be 23, 23.5, 24, 25, or some other number of hours-minutes-seconds.
Duration
If you want to add chunks of 24-hours, use Duration.
Duration d = Duration.ofDays( 3 ) ; // `Duration` defines a “day” as being a 24-hours without regard for the calendar dates.
Or specify in hours, which has the same result in Duration class but would be more clear as to your intent and understanding.
Duration d = Duration.ofHours( 3 * 24 ) ; // Same effect as the `Duration.ofDays( 3 )` seen above.
Add to your Instant.
Instant instantLater = instant.plus( d ) ;
Period
If you meant a day as incrementing a day on the calendar, use Period class. This class represents a number of years-months-days.
Period p = Period.ofDays( 3 ) ; // `Period` defines a day as a date on the calendar without regard for its length in hours.
We cannot add that to Instant without regard for time zone issues. If added to an Instant which is always in UTC we would be using the calendar of UTC. For example, adding a day to a value in UTC might translate to “tomorrow” in India while still being “yesterday” in Québec. A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit, as the default may be changed at any moment during runtime by any code in any thread of any app within the JVM.
Apply your ZoneId to the Instant to get a ZonedDateTime.
ZonedDateTime zdt = instant.atZone( z ) ;
Now you can add days to the ZonedDateTime and the calendar used by the people of that region will be taken into account.
ZonedDateTime zdtLater = zdt.plus( p ) ; // By “later” we assume the number of days in the `Period` is positive. Alternatively, a `Period` could go backwards in time with a negative number of days.
To adjust back to UTC, extract a Instant. We still have the same moment, the same point on the timeline, but with a different wall-clock time.
Instant instantLater = zdtLater.toInstant() ; // Same moment, different wall-clock time.
The elapsed time between zdt and zdtLater may or may not be ( 3 * 24 ) hours. If a DST cutover occurred during that time, the number of hours would be either ( ( 3 * 24 ) - 1 ) in the “Spring Ahead” early in the year, or ( ( 3 * 24 ) + 1 ) in the “Fall Back” of the autumn.
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - 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
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). 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.
Related
I have a method using 2 Instants in parameters getIssuesBillable(Instant start, Instant end, ....), my question is how I get the first day of a month and the last day of the month using a Java 8 Instant?
I already tried use withDayOfMonth(), and lengthOfMonth():
LocalDate initial = LocalDate.now();
LocalDate start = initial.withDayOfMonth(firstDayOfMonth());
LocalDate end = initial.withDayOfMonth(lastDayOfMonth());
But in this case, I need to convert and make some workarounds in this case, if someone knows a better way to do it I really appreciate any response.
tl;dr
Use modern java.time classes.
Here is a brief nonsensical example of starting with an Instant (a moment in UTC), assigning a time zone to view that moment through the wall-clock time used by the people of a particular region (a time zone), extracting the year-and-month as perceived in that time zone, and determining the first and last day of that month, rendering LocalDate objects.
YearMonth // Represent a year-and-month, the entire month as a whole.
.from( // Determine the year-and-month of some other date-time object.
Instant // Represent a moment in UTC.
.now() // Capture the current moment in UTC.
.atZone( // Adjust from UTC to a particular time zone.
ZoneId.of( "Pacific/Auckland" )
) // Returns a `ZonedDateTime` object.
) // Returns a `YearMonth` object.
.atDay( 1 ) // Returns a `LocalDate` object.
…or
…
.atEndOfMonth() // Returns a `LocalDate` object.
By the way, a realistic version of that particular code would be: YearMonth.now( ZoneId.of( "Pacific/Auckland" ) ).atDay( 1 )
Moment versus date-only
Instant is a moment in UTC, a date with time-of-day and an offset-from-UTC of zero.
A LocalDate is a date-only value, without time-of-day and without time zone.
You need to specify the time zone by which you want to perceive the date, the wall-clock time used by the people of a particular region.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Extract the date-only.
LocalDate ld = zdt.toLocalDate() ;
From there, proceed with your other code.
Or work with the month as a whole, using YearMonth class.
YearMonth ym = YearMonth.from( zdt ) ;
LocalDate first = ym.atDay( 1 ) ;
LocalDate last = ym.atEndOfMonth() ;
Tip: You might find helpful the LocalDateRange and Interval classes in the ThreeTen-Extra library.
Tip: Learn about the Half-Open approach to define a span of time, where the beginning is inclusive while the ending is exclusive. So a month starts on the first and runs up to, but does not include, the first day of the following month.
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - 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
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). 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.
For the first day of the month, depends on the time zone:
YearMonth.from(Instant.now().atZone(ZoneId.of("UTC"))).atDay(1);
For the last day of the month, depends on the time zone:
YearMonth.from(Instant.now().atZone(ZoneId.of("UTC"))).atEndOfMonth();
I would like to get the 10 days before today and also set the time to 12:00 midnight
I have figured out that a day has 24 hours so 10 days will have 240 hours so I have
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR, cal.get(Calendar.HOUR) - 240);
The above works but now when I want to set the time to 12:00
I have tried
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
After adding the above the 10 days before are now reset to today.
What could be wrong?
If you are using java.time library it can be more easier, you can use :
LocalDateTime date = LocalDateTime.of(
LocalDate.now().minusDays(10),
LocalTime.of(12, 0)
);
For example :
Now it is :
2018-04-01T13:30
Before 10 days, at 12 it return :
2018-03-22T12:00
You use https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html and method set have this behaviour
set(f, value) changes calendar field f to value. In addition, it sets
an internal member variable to indicate that calendar field f has been
changed. Although calendar field f is changed immediately, the
calendar's time value in milliseconds is not recomputed until the next
call to get(), getTime(), getTimeInMillis(), add(), or roll() is made.
Thus, multiple calls to set() do not trigger multiple, unnecessary
computations. As a result of changing a calendar field using set(),
other calendar fields may also change, depending on the calendar
field, the calendar field value, and the calendar system. In addition,
get(f) will not necessarily return value set by the call to the set
method after the calendar fields have been recomputed. The specifics
are determined by the concrete calendar class.
Example: Consider a GregorianCalendar originally set to August 31,
1999. Calling set(Calendar.MONTH, Calendar.SEPTEMBER) sets the date to September 31, 1999. This is a temporary internal representation that
resolves to October 1, 1999 if getTime()is then called. However, a
call to set(Calendar.DAY_OF_MONTH, 30) before the call to getTime()
sets the date to September 30, 1999, since no recomputation occurs
after set() itself.
You call set three times and result is last set time. So for you purposes you need to use method add after(with) set.
tl;dr
ZonedDateTime.now( // Capture the current moment as seen through the wall-clock time used by the people of a certain region (a time zone).
ZoneId.of( "Pacific/Auckland" ) // Specify a time zone using proper name, `continent/region`, never 3-4 pseudo-codes such as `PST`, `EST`, `IST`.
)
.minusDays( 10 ) // Go back in time ten days, adjusting for time-of-day as need be.
.toLocalDate() // Extract a date-only value.
.atStartOfDay( // Determine the first moment of that date in a certain time zone. Not always 00:00:00.
ZoneId.of( "Pacific/Auckland" )
)
.toString() // Generate a String in standard ISO 8601 format.
2018-03-23T00:00+13:00[Pacific/Auckland]
Avoid legacy date-time classes.
You are using troublesome old date-time classes supplanted years ago by the java.time classes.
java.time
Instead of Calendar, use ZonedDateTime to represent a moment on the timeline with a wall-clock time used by people of a certain region (time zone).
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Capture the current moment.
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit, as the default may be changed at any moment during runtime by any code in any thread of any app within the JVM.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Capture the current moment.
Math
Specify a span of time unattached to the timeline of years-months-days using Period.
Period p = Period.ofDays( 10 ) ;
Go back in time. Anomalies such as Daylight Saving Time (DST) are handled automatically, adjusting time-of-day as need be.
ZonedDateTime zdtTenDaysAgo = zdt.minus( p ) ;
“Midnight” is a trick concept, ambiguous and amorphous. Instead, focus on the idea of “first moment of the day”.
Always let java.time determine the first moment. Do not assume the day starts at 00:00:00. Anomalies such as DST mean the day may start at another time such as 01:00:00. To get that first moment, extract a date-only LocalDate object. Specify a time zone to determine when that date began in that place.
LocalDate ldTenDaysAgo = zdtTenDaysAgo.toLocalDate() ;
ZonedDateTime zdtTenDaysAgoStartOfDay = ldTenDaysAgo.atStartOfDay( z ) ;
If you want to view the same moment as UTC, extract a Instant.
Instant instant = zdtTenDaysAgoStartOfDay.toInstant() ;
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
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
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). 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.
To add or subtract, you should use the add method :
cal.add(Calendar.HOUR, -240);
But beware of that, because a day is not always the same as 24 hours, due to Daylight Saving Time effects: https://www.timeanddate.com/time/dst/transition.html
Anyway, Calendar is a very bugged class and it's better to use java.time classes (API level 26), or threetenbp if java.time is not available: http://www.threeten.org/threetenbp/
See here how to configure in Android: How to use ThreeTenABP in Android Project
To consider DST effects, use a ZonedDateTime:
// current date/time
ZonedDateTime.now()
// minus 10 days
.minusDays(10)
// set time to midnight
.with(LocalTime.MIDNIGHT);
This will take care of the complicated details of DST, including the cases where DST starts at midnight and the day actually starts at 1am - the time is automatically adjusted.
It's not clear if you want midnight (00:00) or noon (12:00). Anyway, if you want noon, just use LocalTime.NOON.
I'm sending date from the Angular app as String to server and converting to java Date object to store in the database.
Also sending timeZoneOffset from UI to use the client's time zone while converting. (After googling I found this approach to get the proper result based on the user location)
Written the following code to convert:
public static void main(String args[]) throws ParseException {
String inputDate = "04/05/2018"; // This date coming from UI
int timeZoneOffset = -330; // This offset coming from UI
// (new Date().getTimeZoneOffset())
getDate(inputDate, timeZoneOffset);
}
public static Date getDate(String inputDate, int timeZoneOffset)
throws ParseException {
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(-timeZoneOffset * 60);
System.out.println("Default time zone: " + TimeZone.getDefault().getID());
TimeZone timeZone = TimeZone.getTimeZone(zoneOffset);
System.out.println("Time zone from offset: " + timeZone.getID());
dateFormat.setTimeZone(timeZone);
Date date = dateFormat.parse(inputDate);
System.out.println("Converted date: " + date);
return date;
}
Expected output:
Default time zone: America/New_York
Time zone from offset: GMT+05:30
Converted date: Thu April 5 00:00:00 IST 2018
Actual result in server:
Default time zone: America/New_York
Time zone from offset: GMT+05:30
Converted date: Wed April 4 14:30:00 EDT 2018
Why is the date decreasing to one day even I set the users time zone? I'm new to Date and Time related concepts and I googled a couple of times didn't find answer, could someone please help on this.
Thanks in advance
The Answer by Godfrey is correct.
tl;dr
LocalDate.parse(
"04/05/2018" ,
DateTimeFormatter.ofPattern( "MM/dd/uuuu" )
)
.atStartOfDay(
ZoneId.of( "Asia/Kolkata" )
)
.toString()
2018-04-05T00:00+05:30[Asia/Kolkata]
For storage in your database, use UTC.
When a new day starts in India, the date at UTC is still “yesterday”, so April 4th rather than April 5th. Same moment, same point on the timeline, different wall-clock time.
LocalDate.parse(
"04/05/2018" ,
DateTimeFormatter.ofPattern( "MM/dd/uuuu" )
)
.atStartOfDay(
ZoneId.of( "Asia/Kolkata" )
)
.toInstant()
2018-04-04T18:30:00Z
java.time
You are using terrible old date-time classes that have proven to be poorly designed, confusing, and troublesome. They are now supplanted by the java.time classes.
Avoid legacy date-time classes entirely
ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(-timeZoneOffset * 60);
…
TimeZone timeZone = TimeZone.getTimeZone(zoneOffset);
You are mixing the modern classes (ZoneOffset) with the troublesome legacy classes (TimeZone). Do not mix the modern classes with the legacy classes. Forget all about the old classes including Date, Calendar, and SimpleDateFormat. The java.time classes are designed to entirely supplant the legacy classes.
Instead of TimeZone, use ZoneId (and ZoneOffset).
LocalDate
Parse your input string as a LocalDate. The LocalDate class represents a date-only value without time-of-day and without time zone.
String input = "04/05/2018" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
LocalDate ld = LocalDate.parse( input , f ) ;
Offset versus Time Zone
int timeZoneOffset = -330;
An offset-from-UTC is not a time zone. An offset is simply a number of hours, minutes, and seconds of displacement from UTC. Your choice of variable name indicates possible confusion on this point.
ZoneOffset offset = ZoneOffset.of( -3 , 30 ) ;
A time zone is a history of past, present, and future changes in offset used by the people of a particular region. So a time zone is always preferable to an offset.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ; // India time zone. Currently uses offset of +05:30 (five and a half hours ahead of UTC).
First moment of the day
You seem to be aiming for the first moment of that date in that zone. Let java.time determine that first-moment-of-the-day. Do not assume that time is 00:00:00. In some zones on some dates, the day may start at another time such as 01:00:00.
ZonedDateTime zdt = ld.atStartOfDay( z ) ; // Determine the first moment of the day on this date in this zone. Not always 00:00:00.
As an example of why you should be using time zones rather than mere offset-from-UTC, look at your example data of -330 which I might easily misinterpret to be three and a half hours behind UTC. This offset is currently only used in the zone America/St_Johns, and only used there for part of the year. So if you applied an offset of -03:30 to a date in the wrong part of the year, your results would be invalid yet go undetected.
Using offset (not recommended)
But your example lacks time zone, so let’s go with offset-from-UTC rather than zone.
Your use of an int integer number to represent an offset-from-UTC is a poor choice of types. First of all, it is ambiguous. That -330 might be interpreted to be a clumsy attempt at -03:30 offset of three and a half hours behind schedule. Secondly, it makes parsing trickier than need be. Thirdly, as a number of minutes, it ignores the possibility of an offset with seconds. Fourthly, you use a negative number for an offset ahead of UTC (apparently) despite common usage and standard usage being the opposite. Lastly, it ignores the clear standard set by ISO 8601 for representing offsets as text: ±HH:MM:SS (and variations). By the way, the padding zero is optional in the standard, but I recommend always including because various libraries and protocols expect it.
Your intent appears to be a number of minutes intended by the integer number.
long seconds =( TimeUnit.MINUTES.toSeconds( - 330 ) * -1 ); // Multiply by negative one to flip the sign to standard ISO 8601 usage, where `+` means “ahead* of UTC and `-` means *behind* UTC.
seconds: 19800
ZoneOffset offset = ZoneOffset.ofTotalSeconds( ( int ) seconds );
offset.toString(): +05:30
Last step: get the first moment of the day in this offset. Caveat: We do not know for certain if this offset is valid on this date, as we lack a time zone.
Convert from the returned ZonedDateTime to an OffsetDateTime. As discussed above, determining first moment of day should always be done with a time zone, and thereby get a ZonedDateTime. We are violating that sensible practice to use an offset, but using the returned ZonedDateTime object would be misleading as ours would lack a true time zone, and have only a mere offset. So the OffsetDateTime class makes our intentions clear and our code more self-documenting.
OffsetDateTime odt = ld.atStartOfDay( offset ).toOffsetDateTime();
Again, this approach using offset is not recommending, as you should be instead gathering a time zone name from the user as input rather than an offset.
UTC
Generally best to store moments in UTC.
Extract a Instant from your OffsetDateTime or ZonedDateTime to get the same moment as UTC.
Instant instant = zdt.toInstant() ;
2018-04-04T18:30:00Z
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
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
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). 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.
It's not decreasing by one day, it is decreasing by 11.5 hours. That happens to be the time difference between GMT+05:30 and "America/New_York", which is GMT-04:30 or GMT-05:30 (depending on time of year).
GMT+05:30 is somewhere in India, I think, since that is about the only place to use a 30 minute offset rather than a whole hour. When it is April 5th in India, it is still April 4th in New York.
The problem may be you aren't getting a time from the client, so it will assume midnight. If you are doing time zone conversion, it is best to include the actual time.
How do I get the time difference from GMT for a specific date and time zone in Java?
Determining whether a specific time zone is in DST is quite straight-forward:
boolean isIsraelInDST = TimeZone.getTimeZone("Israel").inDaylightTime(new Date());
How do I get the actual time difference?
Use TimeZone.getRawOffset(): Returns the amount of time in milliseconds to add to UTC to get standard time in this time zone. Because this value is not affected by daylight saving time, it is called raw offset.
If you want the offset including DST then you use TimeZone.getOffset(long date). You should provide the concrete date to the method, eg now - System.currentTimeMillis()
tl;dr
ZoneId.of( "Pacific/Auckland" ) // Specify a time zone.
.getRules() // Get the object representing the rules for all the past, present, and future changes in offset used by the people in the region of that zone.
.getOffset( Instant.now() ) // Get a `ZoneOffset` object representing the number of hours, minutes, and seconds displaced from UTC. Here we ask for the offset in effect right now.
.toString() // Generate a String in standard ISO 8601 format.
+13:00
For the first moment of a certain date.
ZoneId.of( "Pacific/Auckland" )
.getRules()
.getOffset(
LocalDate.of( 2018 , Month.AUGUST , 23 ) // Specify a certain date. Has no concept of time zone or offset.
.atStartOfDay( ZoneId.of( "Pacific/Auckland" ) ) // Determine the first moment of the day on that date in that region. Not always `00:00:00` because of anomalies such as Daylight Saving Time.
.toInstant() // Adjust to UTC by extracting an `Instant`.
)
.toString()
+12:00
Avoid legacy date-time classes
The other Answers are outmoded, as the TimeZone class is now legacy. This and other troublesome old date-time classes are supplanted by the java.time time classes.
java.time
Now we use ZoneId, ZoneOffset, and ZoneRules instead of the legacy TimeZone class.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
Fetch the rules for that zone.
ZoneRules rules = z.getRules() ;
Ask the rules if Daylight Saving Time (DST) is in effect at a certain moment. Specify the moment as an 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 = Instant.now() ; // Capture current moment in UTC.
boolean isDst = rules.isDaylightSavings( instant ) ;
How do I get the actual time difference?
Not sure what you mean, but I will guess you are asking for the offset-from-UTC in effect at that moment for than zone. An offset is a number of hours, minutes, and seconds displacement from UTC. We represent an offset using ZoneOffset class. A time zone is a history of past, present, and future changes in offset used by the people of a particular region. We represent a time zone using ZoneId class.
Because the offset may vary over time for a region, we must pass a moment when asking for an offset.
ZoneOffset offset = rules.getOffset( instant ) ;
Generate a String representing that offset in ISO 8601 standard format.
String output output = offset.toString() ;
You can ask for the offset as a total number of seconds.
int offsetInSeconds = offset.getTotalSeconds() ;
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.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.
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
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). 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.
I suggest to add summer/winter time offset to getRawOffset:
TimeZone tz1 = TimeZone.getTimeZone("GMT");
TimeZone tz2 = TimeZone.getTimeZone("America/New_York");
long timeDifference = tz1.getRawOffset() - tz2.getRawOffset() + tz1.getDSTSavings() - tz2.getDSTSavings();
I see this is an old thread - but adding this since I had a similar requirement recently -
This gives the actual difference in millis based on the CURRENT time(millis from epoch).
TimeZone.getTimeZone("America/New_York").getOffset(Calendar.getInstance().getTimeInMillis())
public String timeZone(Date date) {
TimeZone timeZone = TimeZone.getTimeZone("America/New_York");
long millis = timeZone.getRawOffset() + (timeZone.inDaylightTime(date) ? timeZone.getDSTSavings() : 0);
return String.format("%s%s:%s",
millis < 0 ? "-" : "+",
String.format("%02d", Math.abs(TimeUnit.MILLISECONDS.toHours(millis))),
String.format("%02d", Math.abs(TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis))))
);
}
I'm trying to grok time-handling, and I've stumbled upon something in Java that has me somewhat baffled. Take this sample code:
public static void main(String[] args)
{
//Calendar set to 12:00 AM of the current day (Eastern Daylight Time)
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT-4"));
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
/////
//Calendar set to 12:00 AM of the current day (UTC time)
Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
utcCal.set(Calendar.HOUR_OF_DAY, 0);
utcCal.set(Calendar.MINUTE, 0);
utcCal.set(Calendar.SECOND, 0);
utcCal.set(Calendar.MILLISECOND, 0);
/////
long oneHourMilliseconds = 3600000;
System.out.println((cal.getTimeInMillis() - utcCal.getTimeInMillis()) / oneHourMilliseconds);
}
I visualize the algorithm for calculating the time represented by cal taking 1 of 2 forms:
Calculate the number of milliseconds from the Epoch, add offset (add -4)
Calculate the number of milliseconds from (Epoch + offset). So # of milliseconds from (Epoch - 4 * oneHourMilliseconds).
Both of these algorithms should yield a result that is 4 hours behind that of utcCal, however running the code returns 4 .
Can someone explain to me why cal, despite being set to a time zone 4 hours behind that of utcCal, ends up having a millisecond value 4 hours after that of utcCal? Shouldn't the code be returning -4?
It's an unfortunate piece of history. A time zone with an ID of "GMT-4" is what you'd expect to be "UTC+4", i.e. it's 4 hours ahead of UTC.
From the etcetera file from tzdb:
# We use POSIX-style signs in the Zone names and the output abbreviations,
# even though this is the opposite of what many people expect.
# POSIX has positive signs west of Greenwich, but many people expect
# positive signs east of Greenwich. For example, TZ='Etc/GMT+4' uses
# the abbreviation "GMT+4" and corresponds to 4 hours behind UTC
# (i.e. west of Greenwich) even though many people would expect it to
# mean 4 hours ahead of UTC (i.e. east of Greenwich).
And from this similar explanation:
If you can at all manage it, avoid definitions and use of the GMT timezones...
The calendar cal is set to 2012-04-18 00:00:00 of the timezone GMT-4.
That moment corresponds to 2012-04-18 04:00:00 in UTC (in other words, when it's 12 AM in the timezone GMT-4, it's 4 AM in UTC).
The calendar utcCal is set to 2012-04-18 00:00:00 of the timezone UTC.
The difference between 2012-04-18 04:00:00 and 2012-04-18 00:00:00 is 4 hours, so you see 4 being printed.
The other Answers are correct. In various contexts the +/- of offset-from-UTC values have opposite meanings.
java.time
In the context of modern java.time classes built into Java 8 and later:
Ahead of UTC, +
Behind UTC, -
So the offset currently used in India (Asia/Kolkata) is +05:30, five and a half hours ahead of UTC. In the America/Regina zone of Canada, the offset currently used is -06:00, six hours behind UTC.
Use zones, not offsets
The big tip here is to always use proper time zone names rather than a mere offset, whenever known.
An offset-from-UTC is simply a number of hours, minutes, and seconds; nothing more, nothing less. A time zone is a history of past, present, and future changes to the offset used by the people of a certain region. So a zone is always preferable to an offset.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
LocalDate ld = LocalDate.now( z ) ;
For four hours ahead of UTC, use a time zone such as Asia/Dubai.
ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( `Asia/Dubai` ) ) ;
zdt.toString(): 2018-03-01T02:39:18.801642+04:00[Asia/Dubai]
For four hours behind UTC, use a time zone such as America/Blanc-Sablon.
ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( `America/Blanc-Sablon` ) ) ;
zdt.toString(): 2018-02-28T18:39:18.801642-04:00[America/Blanc-Sablon]
ZoneOffset
If you are not certain of the intended time zone, and have only an offset-from-UTC, use ZoneOffset class.
ZoneOffset offset = ZoneOffset.ofHoursMinutes( 4 , 30 ) ; // Positive hours is ahead of UTC (east), while negative hours is behind UTC (west).
For UTC itself (an offset of zero), use the constant ZoneOffset.UTC.
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
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
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). 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.