Converting from Joda to Java time - java

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.

Related

Java XMLGregorianCalendar is changing the time - Strange behavior

I have a date as input = 2021-03-12T10:42:01.000Z.... and I want to transform into this format:
String pattern = "yyyy-MM-dd'T'HH:mm:ssZ";
public String getDate(XMLGregorianCalendar input) {
DateFormat f = new SimpleDateFormat(pattern);
input.toGregorianCalendar().setTimeZone(TimeZone.getTimeZone(ZoneOffset.UTC));
String output = f.format(input.toGregorianCalendar().getTime());
System.out.println(output);
}
2021-03-12T12:42:01+0200
Basically, it's adding 2hs more. Maybe it's related with the time zone, I didn't test it in another computer. I have 2 questions:
Why this is happening
What can I do to avoid it? It's a legacy app so I don't want to do a big change
Thanks
Basically, it's adding 2hs more
Not really. It's giving you the output for the same instant in time, but in your system local time zone - because you're creating a SimpleDateFormat without specifying a time zone (or a culture):
DateFormat f = new SimpleDateFormat(pattern);
Personally I'd recommend avoiding using java.text.SimpleDateFormat entirely, preferring the java.time types and formatters. But if you definitely want to use SimpleDateFormat, just make sure you set the time zone to UTC (assuming you always want UTC) and ideally set the culture as well (e.g. to Locale.ROOT).
The Answer by Jon Skeet is correct, and smart. You appear to be seeing simply a time zone adjustment. Your two strings 2021-03-12T10:42:01.000Z & 2021-03-12T12:42:01+0200 represent the very same moment. The 12 noon hour, if two hours ahead of UTC, is the same as 10 AM hour with an offset-from-UTC of zero hours-minutes-seconds.
And, as mentioned in that other Answer, you really should avoid using the terrible date-time classes bundled with the earliest versions of Java.
tl;dr
myXMLGregorianCalendar // Legacy class, representing a moment as seen in some time zone.
.toGregorianCalendar() // Another legacy class, also representing a moment as seen in some time zone.
.toZonedDateTime() // A modern *java.time* class, representing a moment as seen in some time zone.
.toInstant() // Another *java.time* class, for representing a moment as seen in UTC.
.truncatedTo( // Lopping off some smaller part of the date-time value.
ChronoUnit.SECONDS // Specifying whole seconds as our granularity of truncation, so lopping off any fractional second.
) // Returns another `Instant` object, rather than altering (mutating) the original, per immutable objects pattern.
.toString() // Generating text representing the content of our `Instant` object, using standard ISO 8601 format.
java.time
The modern approach uses the java.time classes that years ago supplanted SimpleDateFormat, XMLGregorianCalendar , GregorianCalendar, and such.
Convert legacy <——> modern
You can easily convert from the legacy types to java.time. Look for new to/from methods on the old classes.
ZonedDateTime zdt = myXMLGregorianCalendar.toGregorianCalendar().toZonedDateTime() ;
Adjust to offset of zero
Adjust from whatever time zone to UTC by extracting an Instant. This class represents a moment as seen in UTC, always in UTC.
Instant instant = zdt.toInstant() ;
Understand that zdt and instant both represent the same moment, the same point on the timeline, but differ in their wall-clock time.
Truncation
Given the formatting pattern seen in your Question, you seem want to work with a granularity of whole seconds. To lop off any fractional second, truncate to seconds.
Instant truncated = instant.truncatedTo( ChronoUnit.SECONDS ) ;
ISO 8601
Your desired text format is defined in the ISO 8601 standard. That standard is used by default in java.time for parsing/generating strings. So no need to specify any formatting pattern.
String output = truncated.toString() ;

Convert OffSetDateTime String to ZonedDateTime Java

I have string of the pattern "yyyy-MM-dd'T'HH:mm:ssZ" which I want to convert to ZonedDateTime format using Java.
Input String Example: "2019-11-23T10:32:15+12:24"
Output: ZonedDateTime
Edit: I have tried this but it does not work.
ZonedDateTime convertToZonedDateTime(final String source) {
final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = dateFormat.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}
I have this solution which works for string "2018-04-05 19:58:55" produces output 2018-04-05T19:58:55+05:30[Asia/Kolkata] but when I change the pattern in function to "yyyy-MM-dd'T'HH:mm:ssZ" and input string to 2019-11-23T10:32:15+12:24 it does not work due to ParseException: Unparsable data.
I need ZonedDateTime format for an API which expects the input time in that format.
tl;dr
OffsetDateTime // Represent a moment as a date with time-of-day in the context of an offset-from-UTC (a number of hours-minutes-seconds).
.parse( // Parse text into a date-time object.
"2019-11-23T10:32:15+12:24" // The offset of +12:24 looks suspicious, likely an error.
) // Returns an `OffsetDateTime` object.
Semantically, we are done at this point with a OffsetDateTime object in hand.
But you claim to be using an API that demands a ZoneDateTime object. We have no known time zone to apply, so let’s apply UTC (an offset of zero hours-minutes-seconds).
OffsetDateTime // Represent a moment as a date with time-of-day in the context of an offset-from-UTC (a number of hours-minutes-seconds).
.parse( // Parse text into a date-time object.
"2019-11-23T10:32:15+12:24" // The offset of +12:24 looks suspicious, likely an error.
) // Returns an `OffsetDateTime` object.
.atZoneSameInstant( // Convert from `OffsetDateTime` to `ZonedDateTime` by applying a time zone.
ZoneOffset.UTC // This constant is a `ZoneOffset` object, whose class extends from `ZoneId`. So we can use it as a time zone, though semantically we are making a mess.
) // Returns a `ZonedDateTime` object.
.toString() // Generate text in standard ISO 8601 format.
See this code run live at IdeOne.com.
2019-11-22T22:08:15Z
Caveat: The offset on your example input string looks wrong to me.
Details
You need to understand some concepts for date-time handling.
Offset
A offset-from-UTC is merely a number of hours-minutes-seconds ahead of, or behind, the meridian line drawn at the Greenwich Royal Observatory.
In Java, we represent an offset with the ZoneOffset class. A date and time-of-day in the context of an offset is represented with the OffsetDateTime class. Such an object represents a moment, a specific point on the timeline.
Time zone
A time zone is much more. A time zone is a history of the past, present, and future changes to the offset used by the people of a particular region. These changes are determined by politicians. So these changes can be arbitrary and capricious, and happen surprisingly often, often with little or no warning. In North America, for example, most regions have adopted Daylight Saving Time (DST) nonsense, resulting in the offset changing twice a year. Currently there is a fad amongst politicians to quit DST changes while staying permanently year-round on “summer time”, one hour ahead of standard time.
There is a database cataloging these changes. The tZ data is a file maintained by IANA listing changes worldwide. You’ll likely find copies of this data in your host OS, in enterprise-quality database management systems such as Postgres, and in your Java Virtual Machine. Be sure to keep these up-to-date with changes in zones you care about.
Time zones have names in the format of Continent/Region. For example, Africa/Tunis, Europe/Paris, and Asia/Kolkata.
OffsetDateTime
So an input string like "2019-11-23T10:32:15+12:24" has no indicator of time zone, only an offset. So we must parse it an a OffsetDateTime.
OffsetDateTime odt = OffsetDateTime.parse( "2019-11-23T10:32:15+12:24" ) ;
Asking for that as a ZonedDateTime makes no sense. We cannot reliably determine a time zone merely from an offset. Many time zones may share an offset for some pints in time.
Also, that particular input string 2019-11-23T10:32:15+12:24 is suspect. That offset of twelve hours and twenty-four minutes does not map to any current time zone. Are you sure it is correct?
You can convert your OffsetDateTime to a ZonedDateTime by specifying a time zone to use in adjustment. I suggest using UTC. While this works technically, semantically it is confusing. Moments in UTC are best represented by OffsetDateTime rather than ZonedDateTime. But apparently you are interoperating with code that demands a ZonedDateTime specifically, so c’est la vie.
ZonedDateTime zdt = odt.atZoneSameInstant( ZoneOffset.UTC ) ;
Instant
Tip: Generally, APIs should be written to hand off moments as an Instant object, which is always in UTC by definition.
LocalDateTime
You present another string input, "2018-04-05 19:58:55". This input lacks any indicator of time zone or offset-from-UTC. So we cannot know if this means almost-8PM in Tokyo Japan, or almost-8PM in Toulouse France, or almost-8PM in Toledo Ohio US — which are all events happening several hours apart, different points on the time zone.
Such a value must be parsed as a LocalDateTime. Replace the SPACE in the middle with a T to comply with ISO 8601 standard formatting.
LocalDateTime ldt = LocalDateTime.parse( "2018-04-05 19:58:55".replace( " " , "T" ) ) ;
The resulting object does not represent a moment, is not a point in the timeline. Such an object represents potential moments along a spectrum of about 26-27 hours, the range of time zones around the globe.
ZonedDateTime
If you are certain that input string was intended for a particular time zone, apply a ZoneId to get a ZonedDateTime. Then you have determined a moment, a specific point on the timeline.
ZoneId z = ZonedId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
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.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
You can parse the input date time string into OffsetDateTime and then convert it into ZonedDateTime
String inputDate = "2019-11-23T10:32:15+12:24";
OffsetDateTime offset = OffsetDateTime.parse(inputDate);
ZonedDateTime dateTime = offset.toZonedDateTime();
If you just need ZonedDateTime at same local time with ZoneId then use atZoneSimilarLocal
ZonedDateTime dateTime = offset.atZoneSimilarLocal(ZoneId.systemDefault());
It’s unclear why you think you want a ZonedDateTime, and if you do, in which time zone. A bit of the following has been said already, but I would like to give you three suggestions to choose from:
You don’t need a ZonedDateTime. An OffsetDateTime fits your string better.
If you want a ZonedDateTime in your default time zone, which makes sense, use OffsetDateTime.atZoneSameInstant() (as in the answer by Basil Bourque).
If you just want a ZonedDateTime representation of your string, the one-arg ZonedDateTime.parse() parses it directly.
Use OffsetDateTime
Your string contains an offset, +12:34, and not a time zone, like Pacific/Galapagos. So OffsetDateTime is more correct to represent its content.
String inputStringExample = "2019-11-23T10:32:15+12:24";
OffsetDateTime dateTime = OffsetDateTime.parse(inputStringExample);
System.out.println(dateTime);
Output from this snippet is:
2019-11-23T10:32:15+12:24
I agree with the comment by Basil Bourque, the offset of +12:24 doesn’t look like a real-world UTC offset, but it’s fine for a Stack Overflow example. In 2019 most offsets are on a whole hour and the rest generally on a whole quarter of an hour, so 24 minutes is not used. Historic offsets include many with both minutes and seconds.
I am exploiting the fact that your string is in ISO 8601 format. The classes of java.time parse the most common ISO 8601 variants as their default, that is, without any explicit formatter. Which is good because writing a format pattern string is always error-prone.
Use OffsetDateTime.atZoneSameInstant()
Your call to ZoneId.systemDefault() in the code in the question seems to suggest that you want a ZonedDateTime in your default time zone. On one hand this use of ZonedDateTime seems reasonable and sound. On the other hand relying on ZoneId.systemDefault() is shaky since the default time zone of your JVM can be changed at any time by another part of your program or any ther program running in the same JVM.
ZonedDateTime dateTime = OffsetDateTime.parse(inputStringExample)
.atZoneSameInstant(ZoneId.systemDefault());
System.out.println(dateTime);
Output in my time zone:
2019-11-22T23:08:15+01:00[Europe/Copenhagen]
Parse directly
If you just need a ZonedDateTIme for an API that requires one (for most purposes a poor design), just parse your string into one:
ZonedDateTime dateTime = ZonedDateTime.parse(inputStringExample);
2019-11-23T10:32:15+12:24
Output is indistinguishable from the one we got from OffsetDateTime, but you have got the required type now.
Stay far away from SimpleDateFormat and Date
In the code in your question you tried to use SimpleDateFormat for parsing your string. Since you can use java.time, the modern Java date and time API, stick to it and forget everything about the old date and time classes. The modern API gives you all the functionality you need. In case we had needed a formatter for parsing, the modern DateTimeFormatter would have been the class to use.
What went wrong in your code?
… it does not work due to ParseException: Unparsable data.
Z in your format pattern string is for RFC 822 time zone offset. This is without colon and would have parsed +1224, but not +12:24.
Link
Wikipedia article: ISO 8601

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" );

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)

Getting the Time component of a Java Date or Calendar

Is there a simple or elegant way to grab only the time of day (hours/minutes/seconds/milliseconds) part of a Java Date (or Calendar, it really doesn't matter to me)? I'm looking for a nice way to separately consider the date (year/month/day) and the time-of-day parts, but as far as I can tell, I'm stuck with accessing each field separately.
I know I could write my own method to individually grab the fields I'm interested, but I'd be doing it as a static utility method, which is ugly. Also, I know that Date and Calendar objects have millisecond precision, but I don't see a way to access the milliseconds component in either case.
Edit: I wasn't clear about this: using one of the Date::getTime() or Calendar::getTimeInMillis is not terribly useful to me, since those return the number of milliseconds since the epoch (represented by that Date or Calendar), which does not actually separate the time of day from the rest of the information.
#Jherico's answer is the closest thing, I think, but definitely is something I'd still have to roll into a method I write myself. It's not exactly what I'm going for, since it still includes hours, minutes, and seconds in the returned millisecond value - though I could probably make it work for my purposes.
I still think of each component as separate, although of course, they're not. You can write a time as the number of milliseconds since an arbitrary reference date, or you could write the exact same time as year/month/day hours:minutes:seconds.milliseconds.
This is not for display purposes. I know how to use a DateFormat to make pretty date strings.
Edit 2: My original question arose from a small set of utility functions I found myself writing - for instance:
Checking whether two Dates represent a date-time on the same day;
Checking whether a date is within a range specified by two other dates, but sometimes checking inclusively, and sometimes not, depending on the time component.
Does Joda Time have this type of functionality?
Edit 3: #Jon's question regarding my second requirement, just to clarify: The second requirement is a result of using my Dates to sometimes represent entire days - where the time component doesn't matter at all - and sometimes represent a date-time (which is, IMO, the most accurate word for something that contains year/month/day and hours:minutes:seconds:...).
When a Date represents an entire day, its time parts are zero (e.g. the Date's "time component" is midnight) but the semantics dictate that the range check is done inclusively on the end date. Because I just leave this check up to Date::before and Date::after, I have to add 1 day to the end date - hence the special-casing for when the time-of-day component of a Date is zero.
Hope that didn't make things less clear.
Okay, I know this is a predictable answer, but... use Joda Time. That has separate representations for "a date", "an instant", "a time of day" etc. It's a richer API and a generally saner one than the built-in classes, IMO.
If this is the only bit of date/time manipulation you're interested in then it may be overkill... but if you're using the built-in date/time API for anything significant, I'd strongly recommend that you move away from it to Joda as soon as you possibly can.
As an aside, you should consider what time zone you're interested in. A Calendar has an associated time zone, but a Date doesn't (it just represents an instant in time, measured in milliseconds from the Unix epoch).
Extracting the time portion of the day should be a matter of getting the remainder number of milliseconds when you divide by the number of milliseconds per day.
long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
Date now = Calendar.getInstance().getTime();
long timePortion = now.getTime() % MILLIS_PER_DAY;
Alternatively, consider using joda-time, a more fully featured time library.
Using Calendar API -
Solution 1-
Calendar c = Calendar.getInstance();
String timeComp = c.get(Calendar.HOUR_OF_DAY)+":"+c.get(Calendar.MINUTE)+":"+c.get(Calendar.SECOND)+":"+c.get(Calendar.MILLISECOND);
System.out.println(timeComp);
output - 13:24:54:212
Solution 2-
SimpleDateFormat time_format = new SimpleDateFormat("HH:mm:ss.SSS");
String timeComp = time_format.format(Calendar.getInstance().getTime());
output - 15:57:25.518
To answer part of it, accessing the millisecond component is done like this:
long mill = Calendar.getInstance().getTime();
I don't know what you want to do with the specifics, but you could use the java.text.SimpleDateFormat class if it is for text output.
You can call the getTimeInMillis() function on a Calendar object to get the time in milliseconds. You can call get(Calendar.MILLISECOND) on a calendar object to get the milliseconds of the second. If you want to display the time from a Date or Calendar object, use the DateFormat class. Example: DateFormat.getTimeInstance().format(now). There is also a SimpleDateFormat class that you can use.
To get just the time using Joda-Time, use the org.joda.time.LocalTime class as described in this question, Joda-Time, Time without date.
As for comparing dates only while effectively ignoring time, in Joda-Time call the withTimeAtStartOfDay() method on each DateTime instance to set an identical time value. Here is some example code using Joda-Time 2.3, similar to what I posted on another answer today.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// Joda-Time - The popular alternative to Sun/Oracle's notoriously bad date, time, and calendar classes bundled with Java 7 and earlier.
// http://www.joda.org/joda-time/
// Joda-Time will become outmoded by the JSR 310 Date and Time API introduced in Java 8.
// JSR 310 was inspired by Joda-Time but is not directly based on it.
// http://jcp.org/en/jsr/detail?id=310
// By default, Joda-Time produces strings in the standard ISO 8601 format.
// https://en.wikipedia.org/wiki/ISO_8601
// Capture one moment in time.
org.joda.time.DateTime now = new org.joda.time.DateTime();
System.out.println("Now: " + now);
// Calculate approximately same time yesterday.
org.joda.time.DateTime yesterday = now.minusDays(1);
System.out.println("Yesterday: " + yesterday);
// Compare dates. A DateTime includes time (hence the name).
// So effectively eliminate the time by setting to start of day.
Boolean isTodaySameDateAsYesterday = now.withTimeAtStartOfDay().isEqual(yesterday.withTimeAtStartOfDay());
System.out.println("Is today same date as yesterday: " + isTodaySameDateAsYesterday);
org.joda.time.DateTime halloweenInUnitedStates = new org.joda.time.DateTime(2013, 10, 31, 0, 0);
Boolean isFirstMomentSameDateAsHalloween = now.withTimeAtStartOfDay().isEqual(halloweenInUnitedStates.withTimeAtStartOfDay());
System.out.println("Is now the same date as Halloween in the US: " + isFirstMomentSameDateAsHalloween);
If all you're worried about is getting it into a String for display or saving, then just create a SimpleDateFormat that only displays the time portion, like new SimpleDateFormat("HH:mm:ss"). The date is still in the Date object, of course, but you don't care.
If you want to do arithmetic on it, like take two Date objects and find how many seconds apart they are while ignoring the date portion, so that "2009-09-01 11:00:00" minus "1941-12-07 09:00:00" equals 2 hours, then I think you need to use a solution like Jherico's: get the long time and take it module 1 day.
Why do you want to separate them? If you mean to do any arithmetic with the time portion, you will quickly get into trouble. If you pull out 11:59pm and add a minute, now that your time and day are separate, you've screwed yourself--you'll have an invalid time and an incorrect date.
If you just want to display them, then applying various simple date format's should get you exactly what you want.
If you want to manipulate the date, I suggest you get the long values and base everything off of that. At any point you can take that long and apply a format to get the minutes/hours/seconds to display pretty easily.
But I'm just a little concerned with the concept of manipulating day and time separately, seems like opening a can o' worms. (Not to even mention time zone problems!).
I'm fairly sure this is why Java doesn't have an easy way to do this.
Find below a solution which employs Joda Time and supports time zones.
So, you will obtain date and time (into currentDate and currentTime) in the currently configured timezone in the JVM.
Please notice that Joda Time does not support leap seconds. So, you can be some 26 or 27 seconds off the true value. This probably will only be solved in the next 50 years, when the accumulated error will be closer to 1 min and people will start to care about it.
See also: https://en.wikipedia.org/wiki/Leap_second
/**
* This class splits the current date/time (now!) and an informed date/time into their components:
* <lu>
* <li>schedulable: if the informed date/time is in the present (now!) or in future.</li>
* <li>informedDate: the date (only) part of the informed date/time</li>
* <li>informedTime: the time (only) part of the informed date/time</li>
* <li>currentDate: the date (only) part of the current date/time (now!)</li>
* <li>currentTime: the time (only) part of the current date/time (now!)</li>
* </lu>
*/
public class ScheduleDateTime {
public final boolean schedulable;
public final long millis;
public final java.util.Date informedDate;
public final java.util.Date informedTime;
public final java.util.Date currentDate;
public final java.util.Date currentTime;
public ScheduleDateTime(long millis) {
final long now = System.currentTimeMillis();
this.schedulable = (millis > -1L) && (millis >= now);
final TimeZoneUtils tz = new TimeZoneUtils();
final java.util.Date dmillis = new java.util.Date( (millis > -1L) ? millis : now );
final java.time.ZonedDateTime zdtmillis = java.time.ZonedDateTime.ofInstant(dmillis.toInstant(), java.time.ZoneId.systemDefault());
final java.util.Date zdmillis = java.util.Date.from(tz.tzdate(zdtmillis));
final java.util.Date ztmillis = new java.util.Date(tz.tztime(zdtmillis));
final java.util.Date dnow = new java.util.Date(now);
final java.time.ZonedDateTime zdtnow = java.time.ZonedDateTime.ofInstant(dnow.toInstant(), java.time.ZoneId.systemDefault());
final java.util.Date zdnow = java.util.Date.from(tz.tzdate(zdtnow));
final java.util.Date ztnow = new java.util.Date(tz.tztime(zdtnow));
this.millis = millis;
this.informedDate = zdmillis;
this.informedTime = ztmillis;
this.currentDate = zdnow;
this.currentTime = ztnow;
}
}
public class TimeZoneUtils {
public java.time.Instant tzdate() {
final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now();
return tzdate(zdtime);
}
public java.time.Instant tzdate(java.time.ZonedDateTime zdtime) {
final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS);
final java.time.Instant instant = zddate.toInstant();
return instant;
}
public long tztime() {
final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now();
return tztime(zdtime);
}
public long tztime(java.time.ZonedDateTime zdtime) {
final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS);
final long millis = zddate.until(zdtime, java.time.temporal.ChronoUnit.MILLIS);
return millis;
}
}
tl;dr
LocalTime lt = myUtilDate.toInstant().atZone( ZoneId.of( "America/Montreal" ) ).toLocalTime() ;
Avoid old date-time classes
You are using old legacy date-time classes. They are troublesome and confusing; avoid them.
Instead use java.time classes. These supplant the old classes as well as the Joda-Time library.
Convert
Convert your java.util.Date to an Instant.
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.
Instant instant = myUtilDate.toInstant();
Time Zone
Apply a time zone. Time zone is crucial. For any given moment the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while also being “yesterday” in Montréal Québec.
Apply a ZoneId to get a ZonedDateTime object.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
Local… types
The LocalDate class represents a date-only value without time-of-day and without time zone. Likewise, the LocalTime represents a time-of-day without a date and without a time zone. You can think of these as two components which along with a ZoneId make up a ZonedDateTime. You can extract these from a ZonedDateTime.
LocalDate ld = zdt.toLocalDate();
LocalTime lt = zdt.toLocalTime();
Strings
If your goal is merely generating Strings for presentation to the user, no need for the Local… types. Instead, use DateTimeFormatter to generate strings representing only the date-portion or the time-portion. That class is smart enough to automatically localize while generating the String.
Specify a Locale to determine (a) the human language used for translating name of day, name of month, and such, and (b) the cultural norms for deciding issues such as abbreviation, capitalization, punctuation, and such.
Locale l = Locale.CANADA_FRENCH ; // Or Locale.US, Locale.ITALY, etc.
DateTimeFormatter fDate = DateTimeFormatter.ofLocalizedDate( FormatStyle.MEDIUM ).withLocale( locale );
String outputDate = zdt.format( fDate );
DateTimeFormatter fTime = DateTimeFormatter.ofLocalizedTime( FormatStyle.MEDIUM ).withLocale( locale );
String outputTime = zdt.format( fTime );
About java.time
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.
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.

Categories

Resources