Reputation: 1189
I'm using Android, JUnit and SimpleDateFormat
.
I like to do some conversions between String
and Date
in rfc3339 format with timezone.
Eg: 2017-12-31T23:59:59+02:00
but not 2017-12-31T23:59:59+0200
.
Android SimpleDateFormat
uses Z
pattern but not X
pattern (see RFC3339_REGEX_1
below).
But in my JUnit test (jdk1.8), RFC3339_REGEX_1
does not give me the right format (+02:00
), but +0200
. JUnit test runs well with RFC3339_REGEX_2
.
So how can I do something clean which runs well both on Android device and JUnit test?
public static final String RFC3339_REGEX_1 = "yyyy-MM-dd'T'HH:mm:ssZ"; //android
public static final String RFC3339_REGEX_2 = "yyyy-MM-dd'T'HH:mm:ssXXX"; //java
Upvotes: 1
Views: 1261
Reputation:
The old classes (Date
, Calendar
and SimpleDateFormat
) have lots of problems and design issues, and they're being replaced by the new APIs. And if I'm not wrong, the X
pattern doesn't work in all versions (I know that in JDK 6 it wasn't supported, it was introduced only in JDK 7; not sure how this affects different Android versions).
As an alternative, in Android you can use ThreeTen Backport. To make it work, you'll also need ThreeTenABP (see how to use it here).
If you still need to work with java.util.Date
, though, this API can make things easier to you. If you want a format like 2017-12-31T23:59:59+02:00
, you can convert your java.util.Date
to org.threeten.bp.OffsetDateTime
(using the org.threeten.bp.DateTimeUtils
class to convert the values, and a org.threeten.bp.ZoneOffset
to set the offset to +02:00
):
// assuming that java.util.Date has value equivalent to 2017-12-31T23:59:59+02:00
Date date = ...
// convert to OffsetDateTime (use +02:00 offset)
OffsetDateTime odt = DateTimeUtils.toInstant(date).atOffset(ZoneOffset.of("+02:00"));
System.out.println(odt); // 2017-12-31T23:59:59+02:00
The output will be:
2017-12-31T23:59:59+02:00
Note that this is the result of odt.toString()
(which is called implicity by System.out.println
), and by default it matches the format you want. But you can also enforce a specific format, by using a org.threeten.bp.format.DateTimeFormatter
:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");
System.out.println(fmt.format(odt));
The output is the same. The only difference is that the first version (using toString()
) will print the fractions of second if they're not zero and will omit the seconds if they are zero, and the second version (with a formatter) will always print in the desired format (in this case, print the seconds but not the fraction of seconds), no matter if the values are zero or not.
I believe that, in your case, you're going to need a formatter as you seem to always need a format with seconds and without fraction of seconds.
To convert OffsetDateTime
back to Date
, you can use DateTimeUtils
as well:
// convert back to java.util.Date
date = DateTimeUtils.toDate(odt.toInstant());
If you don't need to work with java.util.Date
, you can use the OffsetDateTime
directly:
// create OffsetDateTime with value = 2017-12-31T23:59:59+02:00
OffsetDateTime odt = OffsetDateTime.of(2017, 12, 31, 23, 59, 59, 0, ZoneOffset.ofHours(2));
Also note that I used ZoneOffset.ofHours(2)
, which is equivalent to ZoneOffset.of("+02:00")
.
You can also get the current date using OffsetDateTime.now(ZoneOffset.ofHours(2))
.
ThreeTen Backport is a backport for new Java 8 date/time classes, and it has many different date and time types (like the OffsetDateTime
above) to be used in different situations. Check this tutorial for more information about what type fits best your case - the tutorial covers Java 8, but the ThreeTen Backport has the same classes and methods names, just the package is different: org.threeten.bp
instead of java.time
.
Upvotes: 2