Time Format String - java

I am trying to decode the date-time receiving from my APIs in my required format "yyyy-MM-dd"
I receive time in 2 format
1. "2022-05-05T11:32:12.542Z"
2. "2022-05-06T07:33:46.59928+00:00"
I am able to decode first format by parsing it using following pattern
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
but not able to understand the format for the 2nd condition.
Some more example example of 2nd Condition
"2022-05-06T06:30:25.583988+00:00"
"2022-05-05T11:32:49.393283+00:00"
P.S. I don't required parsing logic only needed the pattern
Full method used in the code for parsing 1st Condition
fun convertToFormat(src: String): String {
val originalFormat =
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault())
val targetFormat = SimpleDateFormat("yyyy-MM-dd")
val date = originalFormat.parse(src)
return targetFormat.format(date)
}

tl;dr
If you only want to just pull the date portion of the input string, split.
"2022-05-05T11:32:12.542Z"
.split( "T" )
[ 0 ]
If you want to parse the input string, use OffsetDateTime & LocalDate.
OffsetDateTime
.parse(
input
)
.toLocalDate()
.toString() ;
Avoid legacy classes
You are using terrible date-time classes that were years ago supplanted by the modern java.time classes defined by JSR 310. Never use SimpleDateFormat, Date, Calendar.
ISO 8601
Both of your exemple strings represent a moment as seen with an offset from UTC of zero hours-minutes-seconds.
Both of your example strings are in standard ISO 8601 format. The java.time classes support ISO 8601 formats by default when parsing/generating text. So no need to specify a formatting pattern.
Instant
Parse your input as objects of class Instant.
Instant instant1 = Instant.parse( "2022-05-05T11:32:12.542Z" ) ;
Instant instant2 = Instant.parse( "2022-05-06T07:33:46.59928+00:00" ) ;
See this code run live at IdeOne.com.
LocalDate
You want date only. So convert to the more flexible OffsetDateTime, and extract LocalDate.
LocalDate ld = Instant.atOffset( ZoneOffset.UTC ).toLocalDate() ;
Then call LocalDate#toString to generate text in ISO 8601 format YYYY-MM-DD.
Android
The java.time classes are built into Java 8 and later.
Android 26+ carries an implementation of java.time. For earlier Android, the latest tooling provides most of the functionality via “API desugaring”.

I was looking the SimpleDateFormat Docs, and found this reference: https://developer.android.com/reference/kotlin/java/text/SimpleDateFormat#examples
The pattern "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" 2001-07-04T12:08:56.235-07:00, looks like very similar with this you are receiving (except about the seconds precision).

Related

Converting from Joda to Java time

I need to convert joda time to Java time but having some issues
My joda time code :
p.s method is a long type (long argDateString)
DateTime istime = new DateTime(argDateString*1000);
DateTime NormalTime = istime.withZone(DateTimeZone.forID("UTC"));
return normalTime.toString();
My Java code :
Date istime = new date(argDateString*1000);
DateFormat normalTime = DateFormat.getDateTimeInstance(DateFormat.Full, DateFormat.Full);
Return normalTime.format(istime);
With Joda I was getting
1970-01-15T05:45:05.000Z
With Java I am getting
15 January 1970 05:45:05 o'clock UTC
So is there a way to get what i was getting with Joda time ?
Thanks
tl;dr
java.time.Instant
.ofEpochSecond(
Long.parseLong( input )
)
.toString()
Details
Never use Date and DateFormat classes. These are terribly flawed, and are now legacy. They were supplanted by the modern java.time classes defined in JSR 310. The java.time framework is the official successor to the Joda-Time project, both being led by the same man, Stephen Colebourne.
Your first bit of code makes no sense: argDateString*1000. Strings cannot be multiplied.
I suspect your text holds a number of seconds since the first moment of 1970 as seen in UTC. If so, use Long class to parse to a long primitive.
long seconds = Long.parseLong( input ) ; // Parse text into a number.
Pass that number to a static factory method for Instant.
Instant instant = Instant.ofEpochSecond( seconds ) ;
Now you have an object whose value represents a moment, a point on the timeline, as seen in UTC.
To generate text in your desired standard ISO 8601 format, merely call toString. The java.time classes use the ISO 8601 formats by default when generating/parsing text.
String output = instant.toString() ;
All this has been covered many times on Stack Overflow. Search to learn more.

Setting TimeZone works but seems backwards

I have receiving a date in UTC format but needed to display it in my local timezone (EDT).
Stumbled across the following link :
How to set time zone of a java.util.Date?
Which provide this following answer :
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");
I added the following line of code :
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
And what do you know it worked.
Trying to understand what happened and it seems a bit backwards.
I would have expected to have to enter EDT to convert from UTC to EDT but it appears to be the opposite.
isoFormat.setTimeZone(TimeZone.getTimeZone("EDT"));
Per the Java Docs for DateFormat it reads ....
And based on the above, it seems like I should be providing the TimeZone I want and not what I am converting from.
Can you explain what am I missing or misinterpreting?
If I enter in UTC, how is it getting EDT to know to convert it correct?
Can anyone fill in the blanks on how I should have know they were asking for the "From" TimeZone?
tl;dr
Use java.time classes.
LocalDateTime
.parse( "2021-07-23T00:00" )
.atOffset( ZoneOffset.UTC )
.atZoneSameInstant( ZoneId.of( "America/Montreal" ) )
.format(
DateTimeFormatter
.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( Locale.CANADA_FRENCH )
)
Details
You are using terrible date-time classes that were years ago supplanted by the modern java.time classes.
Apparently your input strings are in standard ISO 8601 format. The java.time classes use ISO 8601 formats by default when parsing or generating text. So no need to define a custom formatting pattern.
String input = "2021-07-23T01:23:45" ;
LocalDateTime ldt = LocalDateTime.parse( input ) ;
Apparently you know for certain that the input was meant to be seen as a date and time in UTC, that is, having an offset-from-UTC of zero hours-minutes-seconds. If so, educate them publisher of your data to convince them to supply that string with a +00:00 or Z on the end to express that intention.
Meanwhile, we can assign an offset of zero to instantiate a OffsetDateTime.
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;
And you apparently want to adjust that date-time to a particular time zone. Apply a ZoneId to get a ZonedDateTime object.
You asked for EDT. Unfortunately, such 2-4 letter codes are not a real time zone. Real time zone names are in format of Continent/Region such as Europe/Paris. Perhaps you meant a time zone such as America/New_York.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
A java.util.Date object simply represents an instant on the timeline — a wrapper around the number of milliseconds since the UNIX epoch (January 1, 1970, 00:00:00 GMT). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone e.g.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
isoFormat.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");
isoFormat.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String strDateUtc = isoFormat.format(date);
System.out.println(strDateUtc);
isoFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String strDateNewYork = isoFormat.format(date);
System.out.println(strDateNewYork);
}
}
Output:
2010-05-23T09:01:02
2010-05-23T05:01:02
ONLINE DEMO
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*.
Solution using java.time, the modern Date-Time API:
The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards.
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
LocalDateTime ldt = LocalDateTime.parse("2010-05-23T09:01:02");
ZonedDateTime zdtUtc = ldt.atZone(ZoneId.of("Etc/UTC"));
System.out.println(zdtUtc);
ZonedDateTime zdtNewYork = zdtUtc.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println(zdtNewYork);
}
}
Output:
2010-05-23T09:01:02Z[Etc/UTC]
2010-05-23T05:01:02-04:00[America/New_York]
ONLINE DEMO
Note: For any reason, if you need to convert this object of ZonedDateTime to an object of java.util.Date, you can do so as follows:
Date date = Date.from(zdtUtc.toInstant());
or
Date date = Date.from(zdtNewYork.toInstant());
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.
First thing Java doesn't support EDT abbreviation instead use "EST5EDT". If something is not found it falls EST5EDT.
You can check full list of available timezones
In SimpleDateFormatter if you are using parse() it means you trying to read "from" something. If you are using format() it means you are trying to write "to" something.
Conclusion, In the case of parse() timezone act as input format but in case of format() it acts as output format. The below program converts an EDT date to IST date. Probably using the comments in the below example you will understand what exactly is happening.
// EDT Formatter
SimpleDateFormat edtFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
edtFormat.setTimeZone(TimeZone.getTimeZone("EST5EDT"));
// IST Formatter
SimpleDateFormat istFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
istFormat.setTimeZone(TimeZone.getTimeZone("IST"));
// Convert EDT to IST
String edtDate = "2010-05-23T00:00:00";
Date date = edtFormat.parse(edtDate); //Parse from EDT to Local Timezone
String istDate = istFormat.format(date); //Parse from Local Timezone to IST
System.out.println("EDT: "+edtDate);
System.out.print("Local Date: ");
System.out.println(date);
System.out.println("IST: "+istDate);
I understand java's inital release of java.util.Date was very badly designed which created a lot of confusion that is why later they introduced java.time api whose name are way clear like LocalDate, ZonedDate etc.

Parsing in time string in Java

I have a specification which would return the payment history JSON after successful transaction. 3rd party JSON response has a field for the total time taken for the transaction. As example total time spent while doing the payment history was "00:10:10.0". How do I convert this format this String object to integer primitive.
If you don't mind using external library, then using Joda's org.joda.time.LocalTime can help with the string parsing:
String duration = "00:10:10.0";
int seconds = LocalTime.parse(duration).getMillisOfDay() / 1000;
//returns 610
Please note, that since you're complying to ISO formatting you don't even need to explicitly specify the parsed format.
Also, if you're using Java 8 already, than Joda was used as an inspiration for the new date/time library available there, therefore you'll find a similar class in the standard library: LocalTime
The answer by Radyk is correct. Since the Question mentions ISO 8601 Duration, I will add that string output.
java.time
The java.time framework is built into Java 8 and later. Inspired by Joda-Time. Extended by the ThreeTen-Project. Brought to Java 6 & 7 by the ThreeTen-Backport project, and to Android by the ThreeTenABP project.
String durationAsLocalTimeString = "00:10:10.0";
LocalTime durationAsLocalTime = LocalTime.parse( durationAsLocalTimeString );
Duration duration = Duration.between( LocalTime.MIN , durationAsLocalTime );
String output = duration.toString();
PT10M10S
ISO 8601 Duration Format
That output of PT10M10S is the standard Duration format of PnYnMnDTnHnMnS defined by ISO 8601. The P marks the beginning, the T separates the years-months-days portion from the hours-minutes-seconds portion.
I suggest serializing to strings in this format. Using time-of-day format such as 00:10:10.0 to represent an elapsed time is confusing and error-prone. The ISO 8601 format is obvious and intuitive and solves the ambiguity problem.
Both java.time and Joda-Time use these ISO 8601 formats by default when parsing/generating textual representations of date-time values.
Duration duration = Duration.parse( "PT10M10S" );

Parse Date String to Some Java Object

I am working in a project that reads files and processes data. There I got to work with dates for example:
2012-01-10 23:13:26
January 13, 2012
I found the package Joda, kinda interesting package but don't know if it is the easiest around.
I was able to parse the first example to a DateTime object (Joda) reg-ex and String manipulation. (Ex: by replacing the space by '-' and passing it to constructor.
new DateTime("2012-01-10 23:13:26".replace(' ', '-'))
I guess it worked, but the problem is with the second format. How can I use such an input to extract a an object, preferably a Joda object. I sure can write a function to change the format to what Joda supports, but was wondering if there would be some other way (even some native Java library) to do it.
If there are any thing better than Joda out there, please let me know it as well.
Thank you.
Using Joda-Time, take a look at DateTimeFormat; it allows parsing both kind of date strings that you mention (and almost any other arbitrary formats). If your needs are even more complex, try DateTimeFormatterBuilder.
To parse #1:
DateTimeFormatter f = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
DateTime dateTime = f.parseDateTime("2012-01-10 23:13:26");
Edit: actually LocalDateTime is a more appropriate type for a datetime without a time zone:
LocalDateTime dateTime = f.parseLocalDateTime("2012-01-10 23:13:26");
And for #2:
DateTimeFormatter f = DateTimeFormat.forPattern("MMMM dd, yyyy");
LocalDate localDate = f.parseLocalDate("January 13, 2012");
And yes, Joda-Time is definitely the way to go, as far as Java date & time handling is concerned. :)
As mostly everyone will agree, Joda is an exceptionally user-friendly library. For example, I had never done this kind of parsing with Joda before, but it took me just a few minutes to figure it out from the API and write it.
Update (2015)
If you're on Java 8, in most cases you should simply use java.time instead of Joda-Time. It contains pretty much all the good stuff—or their equivalents—from Joda. For those already familiar with Joda APIs, Stephen Colebourne's Joda-Time to java.time migration guide comes in handy.
Here are java.time versions of above examples.
To parse #1:
DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.from(f.parse("2012-01-10 23:13:26"));
You cannot parse this into ZonedDateTime or OffsetDateTime (which are counterparts of Joda's DateTime, used in my original answer), but that kinda makes sense because there's no time zone information in the parsed string.
To parse #2:
DateTimeFormatter f = DateTimeFormatter.ofPattern("MMMM dd, yyyy");
LocalDate localDate = LocalDate.from(f.parse("January 13, 2012"));
Here LocalDate is the most appropriate type to parse into (just like with Joda-Time).
SimpleDateFormat will parse dates into Java Date objects:
http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html
SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); // first example
SimpleDateFormat format2 = new SimpleDateFormat("MMMMM dd,yyyy"); // second example
Date d1 = format1.parse( dateStr1 );
Date d2 = format2.parse( dateStr2 );
I would imagine Joda has something of a Formatter to do this for you. I found this with a quick google search: http://johannburkard.de/blog/programming/java/date-time-parsing-formatting-joda-time.html
DateTimeFormatter parser1 =
DateTimeFormat.forPattern("dd/MMM/yyyy:HH:mm:ss Z");
DateTimeFormatter parser2 =
DateTimeFormat.forPattern("yyyy-MM-dd HH:mm");
DateTime time = parser1.parseDateTime("<data>");
The syntax that is used to evaluate the patterns can be found in X-Zero's link.
JodaTime is largely considered the de-facto standard for date-time processing in Java - they're working to get it added to the next version of the Java library (well, effectively).
For getting JodaTime dates from strings, you're going to want to look into the DateTimeFormat class.
Easiest would be setting up SimpleDateFormat properly as per the format you would expect and use its parse method to give you a Date object
tl;dr
LocalDateTime ldt = LocalDateTime.parse( "2012-01-10 23:13:26".replace( " " , "T" ) );
…and…
LocalDate localDate = LocalDate.parse ( "January 13, 2012" , DateTimeFormatter.ofLocalizedDate ( FormatStyle.LONG ).withLocale ( Locale.US ) );
Details
The Answer by Jonik is basically correct but misses some important issues.
java.time
If there are any thing better than Joda out there, please let me know it as well.
Yes, there is something better, the java.time framework. The Joda-Time team advises migration to java.time as its successor.
The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
Date-time
Your first input is a date plus a time-of-day. It lacks any offset-from-UTC or time zone info, so we parse it as a LocalDateTime object. The “Local…” means any locality, no specific locality. So it is not an actual moment on the timeline but rather just a rough idea about a moment.
To parse the input string 2012-01-10 23:13:26 we can replace the SPACE in the middle with a T to conform with the canonical style for the ISO 8601 standard format of date-time values.
The java.time classes use ISO 8601 formats by default when parsing and generating textual representations of date-time values. So no need to define a parsing pattern.
String input = "2012-01-10 23:13:26".replace( " " , "T" );
LocalDateTime ldt = LocalDateTime.parse( input );
If you know the the intended time zone from the context of this value, apply it to define an actual moment on the timeline.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ldt.atZone( zoneId );
Dump to console.
System.out.println ( "input: " + input + " | zdt: " + zdt );
input: 2012-01-10T23:13:26 | zdt: 2012-01-10T23:13:26-05:00[America/Montreal]
Date-only
The second of you inputs is a date-only value without time-of-day and without time zone. For that we need the LocalDate class.
I recognize the format of that input as complying with the language (English) and cultural norms of the United States. So no need to specify explicitly a formatting pattern. We can simply ask for a formatter that knows that US format by specifying a Locale. We specify FormatStyle.LONG as appropriate for the length of this format.
String input = "January 13, 2012";
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate ( FormatStyle.LONG ).withLocale ( Locale.US );
LocalDate localDate = LocalDate.parse ( input , formatter );
Dump to console.
System.out.println ( "input: " + input + " | localDate: " + localDate );
input: January 13, 2012 | localDate: 2012-01-13

How do I parse RFC 3339 datetimes with Java?

I'm trying to parse the date returned as a value from the HTML5 datetime input field. Try it in Opera to see an example. The date returned looks like this: 2011-05-03T11:58:01Z.
I'd like to parse that into a Java Date or Calendar Object.
Ideally a solution should have the following things:
No external libraries (jars)
Handles all acceptable RFC 3339 formats
A String should be able to be easily validated to see if it is a valid RFC 3339 date
tl;dr
Instant.parse( "2011-05-03T11:58:01Z" )
ISO 8601
Actually, RFC 3339 is but a mere self-proclaimed “profile” of the actual standard, ISO 8601.
The RFC is different in that it purposely violates ISO 8601 to allow a negative offset of zero hours (-00:00) and gives that a semantic meaning of “offset unknown“. That semantic seems like a very bad idea to me. I advise sticking with the more sensible ISO 8601 rules. In ISO 8601, having no offset at all means the offset is unknown – an obvious meaning, whereas the RFC rule is abstruse.
The modern java.time classes use the ISO 8601 formats by default when parsing/generating strings.
Your input string represents a moment in UTC. The Z on the end is short for Zulu and means UTC.
Instant (not Date)
The modern class Instant represents a moment in UTC. This class replaces java.util.Date, and uses a finer resolution of nanoseconds rather than milliseconds.
Instant instant = Instant.parse( "2011-05-03T11:58:01Z" ) ;
ZonedDateTime (not Calendar)
To see that same moment through the wall-clock time used by the people of a certain region (a time zone), apply a ZoneId to get a ZonedDateTime. This class ZonedDateTime replaces the java.util.Calendar class.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.
Converting
I strongly recommend avoiding the legacy date-time classes when possible. But if you must inter-operate with old code not yet updated to java.time, you may convert back-and-forth. Call new methods added to the old classes.
Instant replaces java.util.Date.
java.util.Date myJUDate = java.util.Date.from( instant ) ; // From modern to legacy.
Instant instant = myJUDate.toInstant() ; // From legacy to modern.
ZonedDateTime replaces GregorianCalendar.
java.util.GregorianCalendar myGregCal = java.util.GregorianCalendar.from( zdt ) ; // From modern to legacy.
ZonedDateTime zdt = myGregCal.toZonedDateTime() ; // From legacy to modern.
If you have a java.util.Calendar that is actually a GregorianCalendar, cast.
java.util.GregorianCalendar myGregCal = ( java.util.GregorianCalendar ) myCal ; // Cast to the concrete class.
ZonedDateTime zdt = myGregCal.toZonedDateTime() ; // From legacy to modern.
Bulleted concerns
Regarding your Question’s specific issues…
No external libraries (jars)
The java.time classes are built into Java 8, 9, 10, and later. An implementation is also included in later Android. For earlier Java and earlier Android, see the next section of this Answer.
Handles all acceptable RFC 3339 formats
The various java.time classes handle every ISO 8601 format I know of. They even handle some formats that mysteriously disappeared from later editions of the standard.
For other formats, see the parse and toString methods of the various classes such as LocalDate, OffsetDateTime, and so on. Also, search Stack Overflow as there are many examples and discussions on this topic.
A String should be able to be easily validated to see if it is a valid RFC 3339 date
To validate input strings, trap for DateTimeParseException.
try {
Instant instant = Instant.parse( "2011-05-03T11:58:01Z" ) ;
} catch ( DateTimeParseException e ) {
… handle invalid input
}
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.
So, in principle this would be done using different SimpleDateFormat patterns.
Here a list of patterns for the individual declarations in RFC 3339:
date-fullyear: yyyy
date-month: MM
date-mday: dd
time-hour: HH
time -minute: mm
time-second: ss
time-secfrac: .SSS (S means millisecond, though - it is not clear what would happen if there are more or less than 3 digits of these.)
time-numoffset: (like +02:00 seems to be not supported - instead it supports the formats +0200, GMT+02:00 and some named time zones using z and Z.)
time-offset: 'Z' (not supporting other time zones) - you should use format.setTimezone(TimeZone.getTimeZone("UTC")) before using this.)
partial-time: HH:mm:ss or HH:mm:ss.SSS.
full-time: HH:mm:ss'Z' or HH:mm:ss.SSS'Z'.
full-date: yyyy-MM-dd
date-time: yyyy-MM-dd'T'HH:mm:ss'Z' or yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
As we can see, this seems not to be able to parse everything. Maybe it would be a better idea to implement an RFC3339DateFormat from scratch (using regular expressions, for simplicity, or parsing by hand, for efficiency).
Just found that google implemented Rfc3339 parser in Google HTTP Client Library
https://github.com/google/google-http-java-client/blob/dev/google-http-client/src/main/java/com/google/api/client/util/DateTime.java
Tested. It works well to parse varies sub seconds time fragment.
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import com.google.api.client.util.DateTime;
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.withZone(ZoneId.of("UTC"));
#Test
public void test1e9Parse() {
String timeStr = "2018-04-03T11:32:26.553955473Z";
DateTime dateTime = DateTime.parseRfc3339(timeStr);
long millis = dateTime.getValue();
String result = formatter.format(new Date(millis).toInstant());
assert result.equals("2018-04-03T11:32:26.553Z");
}
#Test
public void test1e3Parse() {
String timeStr = "2018-04-03T11:32:26.553Z";
DateTime dateTime = DateTime.parseRfc3339(timeStr);
long millis = dateTime.getValue();
String result = formatter.format(new Date(millis).toInstant());
assert result.equals("2018-04-03T11:32:26.553Z");
}
#Test
public void testEpochSecondsParse() {
String timeStr = "2018-04-03T11:32:26Z";
DateTime dateTime = DateTime.parseRfc3339(timeStr);
long millis = dateTime.getValue();
String result = formatter.format(new Date(millis).toInstant());
assert result.equals("2018-04-03T11:32:26.000Z");
}
With the format you have e.g. 2011-05-03T11:58:01Z, below code will do. However, I recently tryout html5 datetime in Chrome and Opera, it give me 2011-05-03T11:58Z --> do not have the ss part which cannot be handled by code below.
new Timestamp(javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar(date).toGregorianCalendar().getTimeInMillis());
Maybe not the most elegant way, but certainly working one I recently made:
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
cal.setTime(sdf.parse(dateInString.replace("Z", "").replace("T", "-")));
Though, The question is very old, but it may help one who wants it Kotlin version of this answer. By using this file, anyone can convert a Rfc3339 date to any date-format. Here I take a empty file name DateUtil and create a function called getDateString() which has 3 arguments.
1st argument : Your input date
2nd argument : Your input date pattern
3rd argument : Your wanted date pattern
DateUtil.kt
object DatePattern {
const val DAY_MONTH_YEAR = "dd-MM-yyyy"
const val RFC3339 = "yyyy-MM-dd'T'HH:mm:ss'Z'"
}
fun getDateString(date: String, inputDatePattern: String, outputDatePattern: String): String {
return try {
val inputFormat = SimpleDateFormat(inputDatePattern, getDefault())
val outputFormat = SimpleDateFormat(outputDatePattern, getDefault())
outputFormat.format(inputFormat.parse(date))
} catch (e: Exception) {
""
}
}
And now use this method in your activity/fuction/dataSourse Mapper to get Date in String format like this
getDate("2022-01-18T14:41:52Z", RFC3339, DAY_MONTH_YEAR)
and output will be like this
18-01-2022
For future reference, as an alternative, you could use ITU[1] which is hand-written to deal with exactly RFC-3339 parsing and also lets you easily deal with leap seconds. The library is dependency-free and only weighs in at 18 kB.
Full disclosure: I'm the author
try
{
final OffsetDateTime dateTime = ITU.parseDateTime(dateTimeStr);
}
catch (LeapSecondException exc)
{
// The following helper methods are available let you decide how to progress
//int exc.getSecondsInMinute()
//OffsetDateTime exc.getNearestDateTime()
//boolean exc.isVerifiedValidLeapYearMonth()
}
[1] - https://github.com/ethlo/itu
I'm using this:
DateTimeFormatter RFC_3339_DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
.append(ISO_LOCAL_DATE_TIME)
.optionalStart()
.appendOffset("+HH:MM", "Z")
.optionalEnd()
.toFormatter();
Example:
String dateTimeString = "2007-05-01T15:43:26.3452+07:00";
ZonedDateTime zonedDateTime = ZonedDateTime.from(RFC_3339_DATE_TIME_FORMATTER.parse(dateTimeString));
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(datetimeInFRC3339format)

Categories

Resources