I have a String like this:
String timeString = "2230"
And I want to convert it into Time type.
I have tried to use this
def bookingTime = new Date().parse("2230")
But it doesn't work. Any ideas?
Thank you for the help!
Try (Groovy implementation):
String timeString = "2230"
def bookingTime = Date.parse("HHmm", timeString)
I do not know Groovy well, but I assume it does not have its own libraries, at least for date-time work. So this answer is aimed at Java libraries.
Date-Time versus Time-Of-Day
I want to convert it into Time type.
Apparently you want to represent only a time-of-day without any date or time zone.
The java.util.Date/.Calendar classes bundled with Java represent a combination of date and time-of-day. (By the way, these classes are notoriously troublesome, confusing, and flawed. Avoid them.)
So, Java 7 and earlier has no "Time" type. Java has had a java.sql.Time, but this class is a hack. A .Time is a j.u.Date with its date portion set to first day of 1970 UTC (the epoch). This class is only intended for use with databases and JDBC, and even then is supplanted by java.time (see below).
Instead you should use either:
Joda-Time library
java.time package (built into Java 8, inspired by Joda-Time, defined by JSR 310)
Both of these libraries offer a LocalTime class (Joda-Time, java.time) to represent a time-only value without date and without time zone.
Joda-Time
Some example code in Joda-Time 2.5, using Java syntax rather than Groovy.
If your input string had colons it would follow standard ISO 8601 format. The standard formats are used in both Joda-Time and java.time by default for parsing and generating strings.
LocalTime localTime = LocalTime.parse( "18:55" ); // ISO 8601 format used by default.
System.out.println( "localTime: " + localTime ); // localTime: 18:55:00.000
With your non-standard format, you must specify a formatter.
LocalTime localTime2 = DateTimeFormat.forPattern( "HHmm" ).parseLocalTime( "2230" );
System.out.println( "localTime2: " + localTime2 ); // localTime2: 22:30:00.000
Related
I want to build a string with the locale date and hour, concatenated, that must be human readable and compatible with the most common OS file allowed characters as well. Something like:
6-23-20_03-06-50
I am using this as an automated filename suggestion for the user.
To achieve this, I have written the following code:
public class CustomDateProvider {
private static final String TWO_DIGIT_PATTERN = "%02d";
public static String getDashedDateAndHourFromDate(Date date) {
ZonedDateTime dateTime = date.toInstant().atZone(ZoneId.systemDefault());
int hour = dateTime.getHour();
int minute = dateTime.getMinute();
int second = dateTime.getSecond();
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
String localeDate = dateFormat.format(date);
String dashedDate = localeDate.replace("/", "-");
return dashedDate
+ "_"
+ String.format(TWO_DIGIT_PATTERN, hour)
+ "-"
+ String.format(TWO_DIGIT_PATTERN, minute)
+ "-"
+ String.format(TWO_DIGIT_PATTERN, second);
}
}
Thus, I am assuming the date separator char will always be "/", and I am not sure if this is always correct.
Either way, there are probably better ways to achieve my goal, and I would appreciate any improvement.
java.time
You are using terrible date-time classes that were years ago supplanted by the modern java.time classes.
Avoid localized formats
You asked for text representing the date-time value in various localized formats. That approach is unwise in a file name.
Localized formats may well contain characters that would be problematic on various file systems. Your example MM/dd/yyyy format using slash characters might cause problems on some Unix/POSIX-oriented file systems.
Localized formats may be misinterpreted by humans who assume a different custom.
Localized formats may make difficult or impossible parsing that string back to a date-time value.
Instead, I strongly recommend using only standard ISO 8601 formats.
“Basic” variant of ISO 8601
You asked for:
must be human readable and compatible
I suggest sticking with the "basic" variant of ISO 8601 format that makes minimal use of delimiters. For compatibility with various filesystems you want to avoid slash, backslash, colon, and space characters.
The ISO 8601 format is in order of significance: year, month, day, hour, minute, second, fractional second. An uppercase T separates the date portion from the time-of-day portion. Such strings sort alphabetically as chronological.
UTC
I also suggest you stick with UTC (an offset of zero hours-minutes-seconds). For this, use Instant (or OffsetDateTime set to UTC).
Instant instant = Instant.now() ; // Capture current moment as seen in UTC.
Truncate if you do not want fractional seconds or minutes.
Instant instant = Instant.now().truncatedTo( ChronoUnit.MINUTES ) ;
You would do string manipulation to remove the hyphens between the year-month-day and the colons between the hour-minute-second.
String output = instant.replace( "-" , "" ).replace( ":" , "" ) ;
For 2021-01-23T12:30:35Z that would be:
20210123T123035Z
The trailing Z means UTC, and is pronounced “Zulu”.
Zoned moment
If you insist on using the date-time as seen in a particular time zone, use ZonedDateTime.
ZoneId z = ZoneId.systemDefault() ; // Or ZoneId.of( "Africa/Tunis" ) and such.
ZonedDateTime zdt = ZonedDateTime.now().truncatedTo( ChronoUnit.MINUTES ) ;
Specify a formatting pattern.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmss" ) ;
String output = zdt.format( f ) ;
Example:
20210123T123035
I do not recommend omitting the zone or offset, but there you go if you insist.
If you insist your example format of 6-23-20_03-06-50, define a DateTimeFormatter to match.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "M-d-uu'_'HH-mm-ss" ) ;
Allowing single-digit month or day is yet another thing I recommend against. As is the use of a two-digit year.
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.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
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. Hibernate 5 & JPA 2.2 support java.time.
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….
Here is how you can get the locale Date_Time-
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class CurrentDateTimeExample {
public static void main(String[] args) {
LocalDateTime currentDateTime = LocalDateTime.now();
System.out.println("Current Date and Time: "+currentDateTime);
DateTimeFormatter pattern = DateTimeFormatter.ofPattern("uuuu-MM-dd_hh-mm-ss");
System.out.println("Date Time in 12 Hour format - " + currentDateTime.format(pattern));
}
}
For more details please see this Get Locale Date_Time
I am trying to use mongodb to fetch some records with date fields, sample records are shown below, and want convert date field which has been parsed using jayway jsonpath to java.util.Date long integer. long integer converted does not match with the original one. Please help.
Sample records in tester collection:
{
"_id" : ObjectId("5b3fe6f91e618afb473dc644"),
"dateField" : ISODate("2018-07-06T15:46:55.819Z")
}
The Java code for getting records using jongo is as follows :
List<Tester> list= jongo.runCommand("{aggregate : 'tester',pipeline:[],cursor : {batchSize :10}}")
.field("cursor")
.as(Tester.class);
for(Tester t : list)
{
System.out.println("dateField test: : : : "+t.getDateField()+" : : : : "+t.getDateField().getTime());
// Output is perfectly fine : dateField test: : : : Fri Jul 06 21:16:55 IST 2018 : : : : 1530892015819
Gson gson = new Gson();
String str = gson.toJson(t);
DocumentContext docCtx = JsonPath.parse(str);
JsonPath jsonPath = JsonPath.compile("$.dateField");
Object obj = docCtx.read(jsonPath);
System.out.println(obj);
//After parsing with jsonPath the date is retained - Jul 6, 2018 9:16:55 PM
SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aaa");
Date d = format.parse(obj.toString());
System.out.println(d + " : : : " + d.getTime());
//Fri Jul 06 21:16:55 IST 2018 : : : 1530892015000 - Time is not retained
}
Expected :
t.getDateField().getTime() ==== d.getTime()
Please help
Regards
Kris
tl;dr
Your formatting pattern omits the fractional seconds, so no milliseconds appear in the output.
You are using obsolete date-time classes. Use java.time instead.
Example:
Instant // Represent a moment in UTC, with a resolution as fine as nanoseconds.
.parse( "2018-07-06T15:46:55.819Z" ) // Parse a string in standard ISO 8601 format. The `Z` on the end means UTC, pronounced “Zulu”.
.atZone( ZoneId.of( "Asia/Kolkata" ) ) // Adjust from UTC to a desired time zone. Same moment, same point on the timeline, different wall-clock time. Returns a `ZonedDateTime` object.
.toString() // Generate a String in standard ISO 8601 format. Represents the moment in our `ZonedDateTime` object.
Convert from legacy java.util.Date class to modern java.time.Instant, and back again. Example nonsense code:
java.util.Date.from( // Convert from modern `Instant` to legacy `Date`.
myJavaUtilDate.toInstant() // Convert from legacy `Date` to modern `Instant`.
)
java.time
You are using terribly troublesome old date-time classes: Date & SimpleDateFormat. These were supplanted years ago by the modern java.time classes.
Your input 2018-07-06T15:46:55.819Z is in standard ISO 8601 format. The java.time classes use the ISO 8601 formats by default when parsing or generating strings. So no need to specify a formatting pattern.
The Z on the end is pronounced Zulu and means UTC. The Instant class represents a moment in UTC.
Instant instant = Instant.parse( "2018-07-06T15:46:55.819Z" ) ;
Generate an output string in ISO 8601 format.
String output = instant.toString() ;
2018-07-06T15:46:55.819Z
Your code ignores the crucial issue of time zone. Rather than rely implicitly on the JVM’s current default time zone, be explicit with a ZoneId even if that is ZoneId.systemDefault().
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(!). For example, your IST could mean Irish Standard Time, India Standard Time, Iran Standard Time, or something else.
After adjusting from UTC to a specific time zone, we still have the same moment, the same point on the timeline. Only the wall-clock time is different.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ; // Or `ZoneId.systemDefault()`.
ZonedDateTime zdt = instant.atZone( z ) ; // Adjust from UTC to a specific time zone.
Generate an output string in ISO 8601 format extended to append the name of the time zone in square brackets.
String output = zdt.toString() ;
2018-07-06T21:16:55.819+05:30[Asia/Kolkata]
Notice your fractional second (milliseconds) is still intact.
Converting
Perhaps you must interface with an java.util.Date (your Question is not clear), because of old code not yet updated to support java.time.
You will find convenient conversion methods, new methods added to the old classes.
Going from java.util.Date to java.time.Instant.
Instant myInstant = myJavaUtilDate.toInstant() ;
Proceed as shown above. Adjust into your desired time zone, and generate a String.
Going the other direction, from the modern Instant class to the legacy class Date.
java.util.Date myDate = java.util.Date.from( myInstant ) ;
Immutable objects
The java.time classes are designed to be thread-safe, and use the immutable objects pattern. Notice how the code above produces fresh objects based on the original’s values, rather than altering (“mutating”) the original.
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, 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.
new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aaa");
You are discarding the milliseconds part of the input, which results in exactly the difference you see. Use this instead:
new SimpleDateFormat("MMM dd, yyyy hh:mm:ss.SSS aaa");
^^^^
Following code throws the exception when try to parse from the string (2011-12-08T02:01:02+01:00):
image.setLastUpdated(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz")
.parse(imageElement.getAttribute("lastUpdate")))
I have also tried the following format:
image.setLastUpdated(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.parse(imageElement.getAttribute("lastUpdate")));
But I get the same exception:
java.text.ParseException: Unparseable date: "2011-12-08T02:01:02+01:00"
at java.text.DateFormat.parse(DateFormat.java:357)
at com.discavo.ImportManagerGiata.parseImageXML(ImportManagerGiata.java:204)
You need X as the specifier for the UTC offset as it's in ISO-8601 format, as per the SimpleDateFormat documentation.
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX")
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:
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. Your Date-Time string conforms to the ISO 8601 format.
Demo:
import java.time.Instant;
import java.time.OffsetDateTime;
public class Main {
public static void main(String[] args) {
OffsetDateTime odt = OffsetDateTime.parse("2011-12-08T02:01:02+01:00");
System.out.println(odt);
// ########### In case you need Instant ###########
Instant instant = odt.toInstant();
System.out.println(instant);
// Java-12 onwards, you can parse the ISO-8601 compliant Date-Time with timezone
// information directly into Instant
instant = Instant.parse("2011-12-08T02:01:02+01:00");
System.out.println(instant);
}
}
Output:
2011-12-08T02:01:02+01:00
2011-12-08T01:01:02Z
2011-12-08T01:01:02Z
ONLINE DEMO
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).
Note: For any reason, if you need to convert this object of Instant to an object of java.util.Date, you can do so as follows:
Date date = Date.from(instant);
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.
The answer by Jon Skeet is correct. But FYI…
No problem in Joda-Time
The problem presented by this question does not exist if using Joda-Time rather than the mess that is the java.util.Date/Calendar classes bundled with Java.
Joda-Time 2.3 has a variety of built-in parsers, so no need to specify a format in this case. Use methods on the ISODateTimeFormat class to retrieve a variety of formatters designed to parse variations of ISO 8601 formatted strings.
The question fails to account for time zone. So I am showing all three possibilities:
You want the time converted to a specific time zone.Denver in this example.
You want the time adjusted to UTC, for no time offset.Common for storage or further date-time work.
You want to preserve this date-time with its offset.Not usually a good idea, as you have neither the benefit of UTC (no offset and no need to worry about Daylight Saving Time DST or other issues), nor the benefit of a named time zone with rules to handle DST or other issues.
For Desired Time Zone
// For desired time zone. Arbitrarily using 'Denver' as named time zone for this example.
DateTimeZone denverTimeZone = DateTimeZone.forID( "America/Denver" );
org.joda.time.DateTime dateTimeInDenver = org.joda.time.format.ISODateTimeFormat.dateTimeNoMillis().withZone(denverTimeZone).parseDateTime( "2011-12-08T02:01:02+01:00" );
System.out.println( "dateTimeInDenver: " + dateTimeInDenver );
When run…
dateTimeInDenver: 2011-12-07T18:01:02.000-07:00
For UTC
// For UTC (no offset).
org.joda.time.DateTime dateTimeInUTC = org.joda.time.format.ISODateTimeFormat.dateTimeNoMillis().withZoneUTC().parseDateTime( "2011-12-08T02:01:02+01:00" );
System.out.println( dateTimeInUTC );
When run…
2011-12-08T01:01:02.000Z
For Offset As Parsed
// For offset as parsed.
// Least beneficial, as no rules for Daylight Saving Time (DST) or other anomalies can be applied.
org.joda.time.DateTime dateTimeWithOffsetParsed = org.joda.time.format.ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed().parseDateTime( "2011-12-08T02:01:02+01:00" );
System.out.println( "dateTimeWithOffsetParsed: " + dateTimeWithOffsetParsed );
When run…
dateTimeWithOffsetParsed: 2011-12-08T02:01:02.000+01:00
As we know we can get date using Java.util.Date or Calender instance or by using GregorianCalendar instance .
Using class 'SimpleDateFormat' we can parse() or format() function our Date or String.
As we know using parse() or format() function we get output as a String only.
Is there any option available in java to get Date instance in particular format like 'yyyy-MM-dd' or any other format, but final output should be of Date type with this format ?
Date doesn't have a format at all. It is just the representation of time since the standard base time known as The Epoch, namely January 1, 1970, 00:00:00 GMT.
You can only get a String representation of the Date in the format required using the SimpleDateFormat.
Also, parse() method of SDF parses the String representation of the Date to a Date object. format() is the method which gives the formatted String representation of the Date object.
Avoid legacy date-time classes
The old date-time classes bundled with the earliest versions of Java are poorly designed, confusing, and troublesome. Avoid them. Now supplanted by the java.time classes.
Instant
As others said, a java.util.Date represents a moment on the timeline in UTC with a resolution of milliseconds. A java.util.Date has no format at all.
You can convert Date objects to a java.time.Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.
Instant instant = myUtilDate.toInstant();
ZonedDateTime
Assign a time zone in which getting a date makes sense in your scenario. A time zone is crucial to determining a date; for any given moment the date varies around the globe by zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
LocalDate
Now if you want to work with date-only values without a time-of-day and without a time zone, extract a LocalDate object from the ZonedDateTime object.
LocalDate ld = zdt.toLocalDate();
Generating strings
To generate a String representing this LocalDate value in the format you requested, simply call toString. That format of YYYY-MM-DD is a standard ISO 8601 format. The java.time classes use ISO 8601 formats by default when parsing/generating strings. Do not confuse a formatted string with the date-time object. A date-time object has no format, only strings have a format.
String output = ld.toString();
If you want other formats, search Stack Overflow for the class DateTimeFormatter.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
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 (see How to use…).
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.
No it is fixed in toString() method of Date class, You could extend Date if you strictly want this functionality
You could extend the java.util.Date class, and override the default toString() method. You might implement the Decorator pattern (or the Adapter pattern - I'm not certain if there's a distinction really).
The short answer to your question is no. The classes Date and GregorianCalendar don't include a format - you have to have the format separately, either as a String or a SimpleDateFormat.
If you really want to be able to pass an object which has both a date and a format, you could make your own class, which has a GregorianCalendar and a SimpleDateFormat as fields. You could give it a toString method that formats the GregorianCalendar using the SimpleDateFormat.
Your comments suggest your are missing the point that a date-time object is not a string. In both java.util.Date and Joda-Time, a date-time is represented as milliseconds since the Epoch. In Java 8 java.time.* the date-time may be nanoseconds since Epoch. But none of that has any thing to do with strings. We create strings as output, as a translation of those milliseconds/nanoseconds, to be meaningful to humans.
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)