I'm trying to simply add TimeZone information back into a LocalDate before performing some more calculations. The LocalDate came from using the ObjectLab LocalDateCalculator to add days to an existing DateTime but the method needs to return a modified ReadableInstant to form an Interval which I can then inspect.
The code I'm trying amounts to a conversion of Joda LocalDate to Joda DateTime:
LocalDate contextLocalBusinessDate = calculator.getCurrentBusinessDate();
DateTime businessDateAsInContextLocation = new DateTime(contextLocalBusinessDate, contextTimeZone);
The error I get is from Joda's conversion system:
java.lang.IllegalArgumentException: No instant converter found for type: org.joda.time.LocalDate
at org.joda.time.convert.ConverterManager.getInstantConverter(ConverterManager.java:165)
at org.joda.time.base.BaseDateTime.<init>(BaseDateTime.java:147)
at org.joda.time.DateTime.<init>(DateTime.java:192)
I'm looking for a fix to this problem, or a workaround that results in an accurate Interval with full timezone information.
There are various methods on LocalDate for this, including:
LocalDate::toDateTimeAtCurrentTime()
LocalDate::toDateTimeAtStartOfDay()
LocalDate::toDateTime( LocalTime )
LocalDate::toDateTime( LocalTime , DateTimeZone )
You have to be explicit about what you want the time component to be in the resulting DateTime object, which is why DateTime's general-conversion constructor can't do it.
java.time
Quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
A common way to convert a LocalDate to ZonedDateTime is to first convert it to LocalDateTime with 00:00 hours using LocalDate#atStartOfDay and then combine with a ZoneId. An alternative to LocalDate#atStartOfDay is LocalDate#atTime(LocalTime.MIN).
Note that LocalDate#atStartOfDay(ZoneId) is another variant of atStartOfDay. However, it may not return a ZonedDateTime with 00:00 hours on the day of DST transition.
You can convert from ZonedDateTime to OffsetDateTime using ZonedDateTime#toOffsetDateTime.
Demo:
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
// Note: Change the ZoneId as applicable e.g. ZoneId.of("Europe/London")
ZonedDateTime zdt = today.atStartOfDay().atZone(ZoneId.systemDefault());
System.out.println(zdt);
OffsetDateTime odt = zdt.toOffsetDateTime();
System.out.println(odt);
}
}
Output:
2021-07-11T00:00+01:00[Europe/London]
2021-07-11T00:00+01:00
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Related
I am trying to convert datetime in a string to an Instant instance using Java 8 or a utilities package.
For example,
String requestTime = "04:30 PM, Sat 5/12/2018";
to
Instant reqInstant should result in 2018-05-12T20:30:00.000Z
reqString is in the America/Toronto time zone.
This is what I tried
String strReqDelTime = "04:30 PM, Sat 5/12/2018";
Date date = new SimpleDateFormat("hh:mm a, EEE MM/dd/yyyy").parse(requestTime);
Instant reqInstant = date.toInstant();
The above code results in "2018-05-12T23:30:00Z".
How can I do it?
tl;dr
Fix your formatting pattern for unpadded month and day.
Use only java.time classes, never the legacy classes.
Contrived example:
LocalDateTime.parse( // Parse as an indeterminate `LocalDate`, devoid of time zone or offset-from-UTC. NOT a moment, NOT a point on the timeline.
"04:30 PM, Sat 5/12/2018" , // This input uses a poor choice of format. Whenever possible, use standard ISO 8601 formats when exchanging date-time values as text. Conveniently, the java.time classes use the standard formats by default when parsing/generating strings.
DateTimeFormatter.ofPattern("hh:mm a, EEE M/d/uuuu", Locale.US) // Use single-character `M` & `d` when the number lacks a leading padded zero for single-digit values.
) // Returns a `LocalDateTime` object.
.atZone( // Apply a zone to that unzoned `LocalDateTime`, giving it meaning, determining a point on the timeline.
ZoneId.of("America/Toronto") // Always specify a proper time zone with `Contintent/Region` format, never a 3-4 letter pseudo-zone such as `PST`, `CST`, or `IST`.
) // Returns a `ZonedDateTime`. `toString` → 2018-05-12T16:30-04:00[America/Toronto].
.toInstant() // Extract a `Instant` object, always in UTC by definition.
.toString() // Generate a String in standard ISO 8601 format representing the value within this `Instant` object. Note that this string is *generated*, not *contained*.
2018-05-12T20:30:00Z
Use single-digit formatting pattern
You used MM in your formatting pattern, to mean any single-digit value (months January-September) will appear with a padded leading zero.
But your input lacks that padded leading zero. So use a single M.
Ditto for day-of-month I expect: d rather than dd.
Use only java.time
You are using troublesome flawed old date-time classes (Date & SimpleDateFormat) that were supplanted years ago by the java.time classes. The new classes entirely supplant the old. There isn't any need to mix the legacy and modern.
LocalDateTime
Parse as a LocalDateTime because your input string lacks any indicator of time zone or offset-from-UTC. Such a value is not a moment, and it is not a point on the timeline. It is only a set of potential moments along a range of about 26-27 hours.
String input = "04:30 PM, Sat 5/12/2018";
DateTimeFormatter f = DateTimeFormatter.ofPattern("hh:mm a, EEE M/d/uuuu", Locale.US); // Specify locale to determine human language and cultural norms used in translating that input string.
LocalDateTime ldt = LocalDateTime.parse(input, f);
ldt.toString(): 2018-05-12T16:30
ZonedDateTime
If you know for certain that input was intended to represent a moment using the wall-clock time used by the people of the Toronto Canada region, apply a ZoneId to get a ZonedDateTime object.
Assigning a time zone gives meaning to your unzoned LocalDateTime. Now we have a moment, a point on the timeline.
ZoneId z = ZoneId.of("America/Toronto");
ZonedDateTime zdt = ldt.atZone(z); // Give meaning to that `LocalDateTime` by assigning the context of a particular time zone. Now we have a moment, a point on the timeline.
zdt.toString(): 2018-05-12T16:30-04:00[America/Toronto]
Instant
To see that same moment as UTC, extract an Instant. Same moment, different wall-clock time.
Instant instant = zdt.toInstant();
instant.toString(): 2018-05-12T20: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. There isn't any need for strings or for java.sql.* classes.
Where can we obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, 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 seems like the time zone on your computer (server) is US Pacific DST (PDT, GMT-7), but you expect to have the result for US Eastern DST (EDT, GMT-4).
Instant.toString() returns UTC (GMT+0) DateTime in ISO 8601 format. ('Z' at the end means UTC).
SimpleDateFormat treats DateTime String in the default time zone of the computer when it is not specified. And your input does not specify a time zone.
So, you need to do something about in what time zone your input is.
PS.: On my machine in Eastern DST, your code gives me the result exactly as you expected.
For the description, you can read Convert String to Date in Java.
String requestTime = "04:30 PM, Sat 5/12/2018 America/Toronto";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm a, EEE M/dd/yyyy z");
ZonedDateTime zonedDateTime = ZonedDateTime.parse(requestTime, formatter);
System.out.println(zonedDateTime.toInstant());
What went wrong in your attempt?
The SimpleDateFormat uses the system's time-zone by default while you have mentioned that requestTime is in America/Toronto timezone. You should never rely on the default time-zone because when your code will be run on a machine in different time-zone your application may behave in an unexpected manner.
How should you have done it?
Set the time-zone to America/Toronto before parsing. Also, Never use Date-Time formatting/parsing API without a Locale.
Demo:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
String requestTime = "04:30 PM, Sat 5/12/2018";
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm a, EEE MM/dd/yyyy", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("America/Toronto"));
Date date = sdf.parse(requestTime);
Instant reqInstant = date.toInstant();
System.out.println(reqInstant);
}
}
Output:
2018-05-12T20:30:00Z
Do not pollute the clean java.time API with the error-prone java.util API
The java.time API introduced with Java-8 (March 2014) supplants the error-prone and outdated java.util and their formatting API, SimpleDateFormat. It is recommended to stop using the legacy date-time API and switch to the modern date-time API. You tried parsing the date-time string using the legacy API and then switching to the modern API using Date#toInstant while you could have done everything using the modern API.
You should use Date#toInstant to switch to the modern API if you are using an old code/library that uses java.util.Date.
Solution using the modern date-time API
Parse the date-time string to LocalDateTime as it does not have time-zone → Convert the obtained LocalDateTime into ZonedDateTime of the given time-zone → Convert the obtained ZonedDateTime into Instant.
Demo:
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String requestTime = "04:30 PM, Sat 5/12/2018";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("h:m a, EEE M/d/u", Locale.ENGLISH);
// Parse the date-time string to LocalDateTime as it does not have time-zone
LocalDateTime ldt = LocalDateTime.parse(requestTime, dtf);
// Convert the LocalDateTime into ZonedDateTime of the given time-zone
ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Toronto"));
// Convert the ZonedDateTime into Instant
Instant instant = zdt.toInstant();
System.out.println(instant);
}
}
Output:
2018-05-12T20:30:00Z
Note that I prefer u to y with DateTimeFormatter.
An alternative solution using the modern date-time API
You can convert the obtained LocalDateTime directly into an Instant using LocalDateTime#toInstant by supplying it with the time-zone ID.
Instant instant = ldt.toInstant(ZoneId.of("America/Toronto").getRules().getOffset(ldt));
Learn more about the the modern date-time API from Trail: Date Time.
Instant.parse(String) appropriately formatted
I have a timestamp encoded as a String—for example, "2012-02-12T09:08:13.123456-0400", coming from an Oracle database.
The only way that I can think of reading this timestamp, is by using Timestamp.valueOf(), and that requires a format of yyyy-[m]m-[d]d hh:mm:ss[.f...]
I am convinced that this is the only way to read time without losing precision because other ways do not support nanosecond precision included in the example above (".123456").
With that in mind, I can simply trim the needed values, to fit the required format. Hence, the original string would be transformed:
Before: "2012-02-12T09:08:13.123456-0400"
After: "2012-02-12 09:08:13.123456"
If I do this, I remove the "-0400" timezone offset. This comes as a red flag to me, until I saw this post. One of the proposed answers states,
I think the correct answer should be java.sql.Timestamp is NOT timezone specific. Timestamp is a composite of java.util.Date and a separate nanoseconds value. There is no timezone information in this class. Thus just as Date this class simply holds the number of milliseconds since January 1, 1970, 00:00:00 GMT + nanos.
To prove to myself that the offset is not needed, I wrote a simple integration test.
Insert this timestamp into the database: "2015-09-08 11:11:12.123457". Read the database using Java, and print out the details. I get "2015-09-08 11:11:12.123457", which is the same value. This happens to be ok, since my JVM and the Oracle DB are running on the same machine.
Is it a fact that a timezone is not factor in java.sql.Timestamp?
Is there a better way to read that entire timestamp, without losing any precision in Java 7?
tl;dr
org.threeten.bp.OffsetDateTime odt =
OffsetDateTime.parse(
"2012-02-12T09:08:13.123456-0400",
org.threeten.bp.format.DateTimeFormatter.ofPattern( "yyyy-MM-dd'T'HH:mm:ssZ" ) // Specify pattern as workaround for Java 8 bug in failing to parse if optional colon is not present.
)
;
Using java.time
Rather than receiving a String from your database, you should retrieve an object, a date-time object, specifically a java.time object.
The java.time classes supplant the troublesome old date-time classes including java.sql.Timestamp. If your JDBC driver supports JDBC 4.2 and later, you can pass and receive java.time objects directly.
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). So this is equivalent to java.sql.Timestamp including support for the six digits of microseconds of your input data, so no precision lost per the requirements of your Question.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
instant.toString(): 2012-02-12T13:08:13.123456Z
ZonedDateTime
If you want to see that same moment through the lens of a particular region's wall-clock time, apply a ZoneId to get a ZonedDateTime object.
ZoneId z = ZoneId.of( "America/St_Thomas" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString(): 2012-02-12T09:08:13.123456-04:00[America/St_Thomas]
OffsetDateTime
As for your direct Question of how to make sense of the string 2012-02-12T09:08:13.123456-0400 as a date-time value, parse as an OffsetDateTime.
A time zone has a name in the format of continent/region, and represents a history of past, present, and future changes to a region’s offset caused by anomalies such as Daylight Saving Time (DST). We have clue as to the time zone with your string, so we use OffsetDateTime rather than ZonedDateTime.
OffsetDateTime odt = OffsetDateTime.parse( "2012-02-12T09:08:13.123456-0400" ) ;
Well, that line of code above should have worked, but in Java 8 there is a small bug in parsing the offset lacking the optional COLON character between the hours and minutes. So -04:00 in Java 8 will parse but not -0400. Bug fixed in Java 9. Your String is indeed compliant with the ISO 8601 standard for date-time formats used by default in the java.time classes. Tip: Generally best to always format your offsets with the colon, and both hours/minutes and with a padding zero – I've seen other protocols and libraries expect only such full format.
Until you move to Java 9, specify the formatting pattern explicitly rather than rely on the implicit default pattern, as a workaround for this bug.
OffsetDateTime odt =
OffsetDateTime.parse(
"2012-02-12T09:08:13.123456-0400",
DateTimeFormatter.ofPattern( "yyyy-MM-dd'T'HH:mm:ssZ" ) // Specify pattern as workaround for Java 8 bug in failing to parse if optional colon is not present.
)
;
Converting
If your JDBC driver is not yet compliant with JDBC 4.2, retrieve a java.sql.Timestamp object, for use only briefly. Immediately convert to java.time using new methods added to the old date-time classes.
java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
Instant instant = ts.toInstant();
Proceed to do your business logic in java.time classes. To send a date-time back to the database convert from Instant to java.sql.Timestamp.
myPreparedStatement.setTimestamp( … , java.sql.Timestamp.from( instant ) ) ;
Java 6 & 7
In Java 6 & 7, the above concepts still apply, but java.time is not built-in. Use the ThreeTen-Backport library instead. To obtain, see bullets below.
In Java 7, you cannot use JDBC 4.2 features. So we cannot directly access java.time objects from the database through the JDBC driver. As seen above, we must convert briefly into java.sql.Timestamp from Instant. Call the utility methods DateTimeUtils.toInstant(Timestamp sqlTimestamp) & DateTimeUtils.toSqlTimestamp(Instant instant).
java.sql.Timestamp ts = myResultSet.getTimestamp( … ) ;
Instant instant = DateTimeUtils.toInstant( ts ) ;
…and…
java.sql.Timestamp ts = DateTimeUtils.toSqlTimestamp( instant ) ;
myPreparedStatement.setTimestamp( … , ts ) ;
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.
java.sql.Timestamp.valueOf(String) parses the provided time in the current timezone. You can check this by looking at the implementation, which in the end simply calls Timestamp(int year, int month, int date, int hour, int minute, int second, int nano) which calls public Date(int year, int month, int date, int hrs, int min, int sec), which says (emphasis mine):
Allocates a Date object and initializes it so that it represents the instant at the start of the second specified by the year, month, date, hrs, min, and sec arguments, in the local time zone.
It is true that Timestamp doesn't have time zone information (it is just a wrapper with number of seconds since the GMT epoch + nanoseconds), but when loading or storing a Timestamp, JDBC will use the local (default) timezone, unless explicitly declared otherwise.
This means that a Timestamp at 10:00 in your local timezone will end up in the database as an SQL TIMESTAMP at 10:00, and not at - for example - 08:00 if your timezone is 2 hours ahead of GMT; and the reverse when loading.
You are correct that java.sql.Timestamp has no timezone information. Under the covers it is just an instant that is milliseconds since the epoch and the epoch itself is defined with essentially a 0 offset, January 1, 1970, 00:00:00 GMT.
That being said, when working with times, offset always matters and this will lead you into the hell, er, "dynamic world" that is ISO-8601 in Java 8 java.time. The offset matters a lot, unless you are standing in Greenwich, England. If you try to just ignore it you may sometimes guess the day wrong; it is Monday in Greenwich 8 hours earlier than it is Monday in Seattle, for example. I don't think Java8 has a built in DateTimeFormatter for the -0000 variants of ISO-8601, but if you are sure your format is "stable", this would work.
public void java8TimeWTF() {
OffsetDateTime odt = OffsetDateTime.parse(
"2012-02-12T09:08:13.123456-0400",
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.nZ"));
Instant i = odt.toInstant();
System.out.printf("odt: %s, i: %s\n", odt, i);
}
Outputs odt: 2012-02-12T09:08:13.000123456-04:00, i: 2012-02-12T13:08:13.000123456Z
Here's what we had to do to deal with all the variant's of ISO-8601 coming out of our clients
import org.testng.annotations.Test;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import static org.testng.Assert.assertEquals;
public class Java8Time8601 {
private final long EXPECTED_MILLIS = 1493397412000L;
public Instant iso8601ToInstant(String s) {
DateTimeFormatter[] dateTimeFormatters = {
DateTimeFormatter.ISO_INSTANT,
DateTimeFormatter.ISO_OFFSET_DATE_TIME,
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ")
};
for (DateTimeFormatter dtf : dateTimeFormatters) {
try {
OffsetDateTime odt = OffsetDateTime.parse(s, dtf);
Instant i = odt.toInstant();
return i;
} catch (DateTimeParseException dtpe) {
;
}
}
throw new IllegalArgumentException(String.format("failed to parse %s", s));
}
#Test
public void testInstantParse8601_Z() throws Exception {
String[] candidates = {
"2017-04-28T16:36:52.000Z",
"2017-04-28T16:36:52.00Z",
"2017-04-28T16:36:52.0Z",
"2017-04-28T16:36:52Z",
"2017-04-28T16:36:52+00:00",
"2017-04-28T16:36:52-00:00",
"2017-04-28T09:36:52-07:00",
"2017-04-28T09:36:52-0700",
};
for (String candidate : candidates) {
Instant i = iso8601ToInstant(candidate);
assertEquals(i.toEpochMilli(), EXPECTED_MILLIS, String.format("failed candidate %s", candidate));
System.out.println(i.toString());
}
}
}
There has got to be a better way.
Is there a way to check if a java Date object is Monday? I see you can with a Calendar object, but date? I'm also using US-eastern date and time if that changes indexing of monday
Something like this will work:
Calendar cal = Calendar.getInstance();
cal.setTime(theDate);
boolean monday = cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY;
You can use Calendar object.
Set your date to calendar object using setTime(date)
Example:
calObj.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY
EDIT: As Jon Skeet suggested, you need to set TimeZone to Calendar object to make sure it works perfect for the timezone.
The question doesn't make sense without two extra pieces of information: a time zone and a calendar system.
A Date object just represents an instant in time. It happens to be Wednesday in the Gregorian calendar in my time zone - but for some folks to the east of me, it's already Thursday. In other calendar systems, there may not even be such a concept of "Monday" etc.
The calendar system part is probably not a problem, but you will need to work out which time zone you're interested in.
You can then create a Calendar object and set both the time zone and the instant represented - or, better, you could use Joda Time which is a much better date/time API. You'll still need to think about the same questions, but your code will be clearer.
You should use Calendar object for these checks. Date has weak timezones support. In one timezone this Date can be Monday, and in another timezone it is still Sunday.
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
Use Instant to represent a moment:
Instant instant = Instant.now();
System.out.println(instant); // A sample output: 2021-07-03T09:07:37.984Z
An Instant represents an instantaneous point on the timeline in UTC. The Z in the output is the timezone designator for a zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
However, if you have got an object of java.util.Date, convert it to Instant e.g.
Date date = new Date(); // A sample date
Instant instant = date.toInstant();
Convert Instant to ZonedDateTime representing Date-Time in your timezone e.g.
ZonedDateTime zdt = instant.atZone(ZoneId.of("America/New_York"));
Check if the Date-Time falls on Monday e.g.
System.out.println(zdt.getDayOfWeek() == DayOfWeek.SUNDAY);
Demo:
import static java.time.DayOfWeek.SUNDAY;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.now();
ZonedDateTime zdt = instant.atZone(ZoneId.of("America/New_York"));
System.out.println(zdt.getDayOfWeek() == SUNDAY);
}
}
Output:
false
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
I want to convert the current time to the time in a specific timezone with Joda time.
Is there a way to convert DateTime time = new DateTime() to a specific timezone, or perhaps to get the number of hours difference between time.getZone() and another DateTimeZone to then do time.minusHours or time.plusHours?
I want to convert the current time to the time in a specific timezone with Joda time.
It's not really clear whether you've already got the current time or not. If you've already got it, you can use withZone:
DateTime zoned = original.withZone(zone);
If you're just fetching the current time, use the appropriate constructor:
DateTime zoned = new DateTime(zone);
or use DateTime.now:
DateTime zoned = DateTime.now(zone);
Check out DateTimeZone & Interval:
DateTime dt = new DateTime();
// translate to London local time
DateTime dtLondon = dt.withZone(DateTimeZone.forID("Europe/London"));
Interval:
Interval interval = new Interval(start, end); //start and end are two DateTimes
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
// ZonedDateTime.now() is same as ZonedDateTime.now(ZoneId.systemDefault()). In
// order to specify a specific timezone, use ZoneId.of(...) e.g.
// ZonedDateTime.now(ZoneId.of("Europe/London"));
ZonedDateTime zdtDefaultTz = ZonedDateTime.now();
System.out.println(zdtDefaultTz);
// Convert zdtDefaultTz to a ZonedDateTime in another timezone e.g.
// to ZoneId.of("America/New_York")
ZonedDateTime zdtNewYork = zdtDefaultTz.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println(zdtNewYork);
}
}
Output from a sample run:
2021-07-25T15:48:10.584414+01:00[Europe/London]
2021-07-25T10:48:10.584414-04:00[America/New_York]
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
We're searching for information on how to format instances of java.util.Calendar and more general information and coding hints regarding transition from using java.util.Date to java.util.Calendar.
best,
phil
My hint would be not to use either Date or Calendar. Use Joda Time instead. It's much, much nicer than the built-in classes. JSR-310 will hopefully, eventually bring something Joda-like into the main library, but for the moment Joda is your best bet.
If you must stick to Date/Calendar, see java.text.DateFormat and java.text.SimpleDateFormat. Remember that they're not thread-safe though :(
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
If you are getting an object of java.util.Date from some API, your first step should be to convert it into Instant using Date#toInstant which can be converted to other types of modern Date-Time API.
A demo with the modern Date-Time API:
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.now();
System.out.println(instant);
ZonedDateTime zdtUtc = instant.atZone(ZoneId.of("Etc/UTC"));
System.out.println(zdtUtc);
ZonedDateTime zdtNewYork = instant.atZone(ZoneId.of("America/New_York"));
System.out.println(zdtNewYork);
// Fixed offset
OffsetDateTime odtUtc = instant.atOffset(ZoneOffset.UTC);
System.out.println(odtUtc);
OffsetDateTime odtWithOffset0530Hours = instant.atOffset(ZoneOffset.of("+05:30"));
System.out.println(odtWithOffset0530Hours);
// OffsetDateTime from ZonedDateTime
OffsetDateTime odtNewYork = zdtNewYork.toOffsetDateTime();
System.out.println(odtNewYork);
// LocalDate in New York
LocalDate todayNewYork = zdtNewYork.toLocalDate();
System.out.println(todayNewYork);
// Alternatively
System.out.println(LocalDate.now(ZoneId.of("America/New_York")));
// LocalDateTime in New York
LocalDateTime nowNewYork = zdtNewYork.toLocalDateTime();
System.out.println(nowNewYork);
// Alternatively
System.out.println(LocalDateTime.now(ZoneId.of("America/New_York")));
// Formatted output
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMMM dd HH:mm:ss z uuuu", Locale.ENGLISH);
System.out.println(dtf.format(zdtNewYork));
}
}
Output:
2021-07-14T19:22:13.544911Z
2021-07-14T19:22:13.544911Z[Etc/UTC]
2021-07-14T15:22:13.544911-04:00[America/New_York]
2021-07-14T19:22:13.544911Z
2021-07-15T00:52:13.544911+05:30
2021-07-14T15:22:13.544911-04:00
2021-07-14
2021-07-14
2021-07-14T15:22:13.544911
2021-07-14T15:22:13.586971
Wed July 14 15:22:13 EDT 2021
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
Some helpful answers using java.time API:
Check this answer and this answer to learn how to use java.time API with JDBC.
How to use ParsePostion?
Timezone conversion.
SimpleDateFormat does not handle fraction-of-second beyond three digits in the millisecond part correctly.
How to convert LocalDate to ZonedDateTime?
'Z' is not the same as Z.
Day-of-month with ordinal.
The standard library does not support a formatted Date-Time object.
Never use SimpleDateFormat or DateTimeFormatter without a Locale.
How to check if timestamp (epoch time) is of today's or yesterday's?
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.