convert string timestamp to ISO 8601 compliant string - java

I have a timestamp and offset in string format as shown below in two different variables:
01/14/2016 07:37:36PM
-08:00
I want to convert above timestamp into ISO 8601 compliant String, with milliseconds and timezone so it should look like this after conversion:
2016-01-14T19:37:36-08:00
How can I do that? I am using jodatime library.

The newer java.time classes work so well with ISO 8601 strings.
String dateTimeString = "01/14/2016 07:37:36PM";
String offsetString = "-08:00";
LocalDateTime dateTime = LocalDateTime.parse(dateTimeString,
DateTimeFormatter.ofPattern("MM/dd/uuuu hh:mm:ssa"));
ZoneOffset offset = ZoneOffset.of(offsetString);
String formattedTimestamp = dateTime.atOffset(offset).toString();
System.out.println(formattedTimestamp);
This prints
2016-01-14T19:37:36-08:00
Stay away from outdated classes like SimpleDateFormat.
What is offsetString is not present? I understand that in this case you want an offset of Z for UTC. For example like this:
ZoneOffset offset;
if (offsetString == null) {
offset = ZoneOffset.UTC;
} else {
offset = ZoneOffset.of(offsetString);
}
String formattedTimestamp = dateTime.atOffset(offset).toString();
With a null offsetString we now get
2016-01-14T19:37:36Z
The classes in java.time (of which I’m using but a few) are described in JSR-310 and come built-in with Java 8. What if you would like to use them with Java 6 or 7? You get the ThreeTen Backport (link below). It gives you the majority of the classes for Java 6 and 7. I’m not perfectly happy to tell you you need an external library, but in this case it’s only until you move to Java 8. I hope you will soon.
I am sure it can be done with JodaTime too, but I haven’t got experience with it, so cannot give you the details there. What I do know, I have read the the folks behind JodaTime now recommend you move over to java.time instead. So I am asking you to swap one external library for a newer (and supposedly better) one. In itself I’m not unhappy with that. Only if you already have a codebase that uses JodaTime, it’s not really trivial.
Link: ThreeTen Backport

You can find more examples in section Examples at :- http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
String string2 = "2001-07-04T12:08:56.235-07:00";
Date result2 = df2.parse(string2);

Related

Convert any ISO-8601 format to a readable format in Android

So, I know this is a problem well discussed upon and a lot of questions and answers (mostly concerning Joda) and also with the new class DateTimeFormatter and all that supports api levels above 26. But my concern is this:
My android application supports 21 and above
I get multiple variations of date/time formats of ISO-8601 from different APIs:
for eg: a) “2020-09-03T17:03:11.719566Z” b) “2021-03-05T18:30:00Z”
So, I require to find #days between today and that date. When I write the code to parse one of them the other hits my catch block and vice versa, so I write a nested try/catch block to handle both the cases...something like this:
fun getFormattedDate(stringDate: String?): Long {
if (dueDateString.isNullOrEmpty())
return 0
val today = Calendar.getInstance().time
try {
val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH)
val date = inputFormat.parse(dueDateString)
return if (date != null) {
val dueCalendar = Calendar.getInstance()
dueCalendar.time = date
getNoOfDays(today.time, dueCalendar.timeInMillis)
} else
0
} catch (ex: Exception) {
ex.showLog()
try {
val inputFormat1 = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH)
val date = inputFormat1.parse(dueDateString)
return if (date != null) {
val dueCalendar = Calendar.getInstance()
dueCalendar.time = date
getNoOfDays(today.time, dueCalendar.timeInMillis)
} else
0
} catch (exc: Exception) {
exc.showLog()
return 0
}
}
}
I am using this function to find #days between two dates:
fun getDueDateAfterParsing(dueDateString: String?): Long {
val today = ZonedDateTime.ofInstant(now(), ZoneId.systemDefault())
val dueDate = ZonedDateTime.parse(
dueDateString,
DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault())
)
return ChronoUnit.DAYS.between(today, dueDate)
}
I am pretty sure that the solution to this cannot be this complex. There are so many formats for ISO-8601 so i cant be writing try/catch blocks that fits for all cases right? So can anybody help me with the most simplest way I can get my way through this?
I have thought about regex too and most of them will end up saying Joda I am guessing, but at-least I want to be sure about what is the most optimal way or the best way of doing this.
Thanks in advance for any help.
java.time and desugaring or ThreeTenABP
You can use DateTimeFormatter and the other classes from java.time, the modern Java date and time API, on Android API level 21 and up in two ways:
Through desugaring.
Through the backport; there is even an Android adaptation of it, ThreeTenABP, already mentioned by chrylis. It’s ThreeTen for JSR-310, where java.time was first described, and ABP for Android backport.
For both ways see the links at the bottom.
Code
You don’t even need to specify a formatter.
String stringWeGot = "2020-09-03T17:03:11.719566Z";
Instant parsed = Instant.parse(stringWeGot);
System.out.println(parsed);
Output:
2020-09-03T17:03:11.719566Z
Or with your other example string:
String stringWeGot = "2021-03-05T18:30:00Z";
2021-03-05T18:30:00Z
The classes of java.time parse the most common ISO 8601 variants as their default, that is, without an explicit formatter. Presence or absence of from 0 through 9 decimals on the seconds is built in, even the presence or absence of the seconds themselves. Both Instant and OffsetDateTime can be used in the manner shown in the code.
Warning! If you do opt for one or more formatters for one reason or another, never hardcode Z as a literal in the format pattern string. Z is an offset (of zero) from UTC and must be parsed as such, or you get incorrect results on the vast majority of Android devices.
Also when it comes to counting days, java.time is far superior to the old and poorly designed classes like Calendar. EDIT: Your method for counting whole days until the due date in the device time zone is correct. Just for reference, my way of doing it would be:
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime today = ZonedDateTime.now(zone);
ZonedDateTime dueDate = parsed.atZone(zone);
long daysUntilDue = ChronoUnit.DAYS.between(today, dueDate);
System.out.println(daysUntilDue);
Using your example string of 2021-03-05T18:30:00Z and running in Europe/Copenhagen time zone just now the result was:
181
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
Java 8+ APIs available through desugaring
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.

How to convert date from English to Arabic

I have this code
frame.sigdate.setText(new SimpleDateFormat("yyyy/M/d").format(new Date()));
which reads the date from my PC with English numbers. What I want to do is convert the date to Arabic numbers.
Is there anything like Local.ar ?
I appreciate any help.
java.time
Locale arabicLocale = Locale.forLanguageTag("ar");
DateTimeFormatter arabicDateFormatter
= DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
.withLocale(arabicLocale)
.withDecimalStyle(DecimalStyle.of(arabicLocale));
LocalDate today = LocalDate.now(ZoneId.of("Asia/Muscat"));
System.out.println(today.format(arabicDateFormatter));
Output:
١٥‏/٤‏/٢٠١٨
The key is withDecimalStyle. Without this call, the formatter would still use western numerals, as in 15‏/4‏/2018. You may want to use a more specific language tag than just ar for Arabic, for example ar-BH for Bahrain or ar-YE for Yemen. See the link at the bottom for possibilities. You should also insert your desired time zone where I put Asia/Muscat.
EDIT: The above has been tested in Java 9. Surprisingly in Java 8 it still uses western (unlocalized) digits. A possible fix (or workaround if you like) is to specify the zero digit explicitly — it will pick up the other digits from it.
DecimalStyle arabicDecimalStyle
= DecimalStyle.of(arabicLocale).withZeroDigit('٠');
DateTimeFormatter arabicDateFormatter
= DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
.withLocale(arabicLocale)
.withDecimalStyle(arabicDecimalStyle);
It’s an Arabic zero between the two apostrophes in the argument to withZeroDigit. Now I get this output on Java 8:
١٥/٠٤/١٨
It’s usually a good idea to use the built-in locale specific formats as I do with ofLocalizedDate in both snippets above. If you need finer control over the format, use ofPattern instead. For example, to get yyyy/mm/dd format:
DateTimeFormatter arabicDateFormatter
= DateTimeFormatter.ofPattern("uuuu/MM/dd", arabicLocale)
.withDecimalStyle(arabicDecimalStyle);
Output:
٢٠١٨/٠٤/١٥
The reason why the format changed from Java 8 to Java 9 is that Java has changed the defaults for where the locale data come from, including the built-in localized date and time formats. You can get the Java 9 format already in Java 8 by setting a system property, for example like this:
System.setProperty("java.locale.providers", "CLDR,JRE,SPI");
With this change the first code snippet above gives the same output on Java 8 as on Java 9:
١٥‏/٤‏/٢٠١٨
The important detail here is that CLDR goes first in the property string. And the advantages are you don’t need to specify your own format pattern string, localization to other locales is straightforward and users won’t be surprised by a change in behaviour once you switch to Java 9 or later.
I am using and recommending java.time, the modern Java date and time API. The SimpleDateFormat class that you used in the question is not only long outdated, it is also notoriously troublesome. IMHO you should avoid it completely. The modern API is so much nicer to work with.
Links
Oracle tutorial: Date Time explaining how to use java.time.
List of supported locales in Java 8
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/MM/yyyy");
String date = "16/08/2011";
Locale arabicLocale = Locale.forLanguageTag("ar-SA");
DateTimeFormatter arabicDateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(arabicLocale).withDecimalStyle(DecimalStyle.of(arabicLocale));
LocalDate today = LocalDate.now(ZoneId.of("Asia/Muscat"));
today = LocalDate.parse(date, formatter);
String dat = today.format(arabicDateFormatter);
System.out.println(dat);
out put ١٦‏/٨‏/٢٠١١
try below approch
java.util.Locale locale = new java.util.Locale("ar");
java.text.DecimalFormat df = (java.text.DecimalFormat)
java.text.DecimalFormat.getNumberInstance(locale);
DateTime dateTimeObjectInUTC = new DateTime(DateTimeZone.UTC);
DateTimeZone dateTimeZoneObject = DateTimeZone.forID("Asia/Riyadh");
java.util.Locale locale = new Locale("ar","SA");
DateTimeFormatter formatter = DateTimeFormat.forStyle("FF").withLocale(locale).withZone(dateTimeZoneObject);
String output = formatter.print(dateTimeObjectInUTC);
This should help!
I am using Joda-Time. Please refer to the Jodatime documentation. DateTimeZone documentation, for example.

Format String into Date considering localization in GWT

I have the problem that I cannot format a String, having in form of "270317" (German version), into a Date.
For accomplishing this, I use GWT.
What I have so far is this:
String input = "270317";
LocaleInfo locale = null;
if (locale == null) {
locale = LocaleInfo.getCurrentLocale();
}
date = DateTimeFormat.getFormat(input).parse(input);
The outcome is always the current date: 07/28/2017
What I want to achieve is to have the date as it is written in the country where the program is being executed.
If that is not really possible then I would prefer to have it written in this way: 03/27/2017.
To parse the input 270317 to a Date, you must provide the expected format (you're using input as the format, which is wrong):
String input = "270317";
Date date = DateTimeFormat.getFormat("ddMMyy").parse(input);
This will parse the date correctly, if the input format is always as day-month-year. If the inputs are produced in a localized format, then you can use DateTimeFormat.getFormat(PredefinedFormat.DATE_SHORT) or any other format - but this is locale-specific and it can vary a lot between different environments.
Check your inputs to know if you'll need to use a fixed or a localized format.
After you parsed the date, you can then format it to whatever format you want. If you want a locale-specific format, just use:
DateTimeFormat.getFormat(PredefinedFormat.DATE_SHORT).format(date);
This is locale specific, so the output can vary. In my system, I've got:
2017-03-27
Java new Date/Time API
Although you're using GWT, this specific code for date parsing/formatting could be handled by a better API. GWT uses java.util.Date, which has lots of problems and design issues.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
To parse and format a date, you can use a DateTimeFormatter. As you're using only day, month and year, I'm using the LocalDate class (which has only the date fields):
String input = "270317";
// parse the date
DateTimeFormatter parser = DateTimeFormatter.ofPattern("ddMMyy");
LocalDate date = LocalDate.parse(input, parser);
// locale specific format
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
System.out.println(formatter.format(date));
As this is locale specific, in my system I've got the output:
27/03/17
If you want to use exactly the same pattern produced by GWT, you can use:
// get the GWT format
String pattern = DateTimeFormat.getFormat(PredefinedFormat.DATE_SHORT).getPattern();
// use the same format in the formatter
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
System.out.println(formatter.format(date));
Based on the GWT docs, it seems to use patterns compatible with DateTimeFormatter (at least for date fields), so this should work for all cases.
If you want a fixed format (like 03/27/2017), just do:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
Check the javadoc for more details about date patterns.

Add interval to a datetime

I want to achieve a similar operation in java:
time = "2014-05-19 13:36:05"
interval = "60 (seconds)"
time - interval = "2014-05-19 13:35:05"
What's the best approach to express this in Java given the following constraints:
The datetime is a formated string.
The interval is an integer.
The calculated time should be also a datetime formatted string.
You should work with "Date" objects, which basically represent an instance in time (number of milliseconds since Unix epoch) when doing the subtraction. Once you have a "Date" Object you can use "getTime" method (http://docs.oracle.com/javase/7/docs/api/java/util/Date.html#getTime()) to get this milliseconds value, and subtract 60 seconds (make sure to work with milliseconds not seconds!), and create a new "Date" with that resulting value.
This is one approach. There are many, Joda library is also quite popular. It has a method to subtract milliseconds from its date representation, http://www.joda.org/joda-time/apidocs/org/joda/time/DateTime.html#minusSeconds(int).
Try using the joda-time library.
Here is the class to parse the date string.
Use:
dateTime.minusSeconds(int sec);
method to substract your interval.
java.time
The modern way is with java.time classes.
Do not conflate a point-in-time (a moment) with a span-of-time (a duration). Avoid representing a span-of-time using time-of-day notation as that creates ambiguity and confusion. Use standard ISO 8601 formatted strings to represent a duration: PnYnMnDTnHnMnS.
Do not conflate a date-time value (object) with a String representation. A date-time object can parse or generate a String but is distinct and separate from the String.
The java.time framework is rich with various date-time classes. Use these to represent your data as objects rather than mere numbers and strings.
The java.time classes use standard ISO 8601 formatted strings by default.
String input = "2014-05-19T13:36:05" ;
LocalDateTime ldt = LocalDateTime.parse( input );
Duration d = Duration.ofSeconds( 60 );
LocalDateTime later = ldt.plus( d );
ld.toString(): 2014-05-19T13:36:05
d.toString(): PT1M
later.toString(): 2014-05-19T13:37:05
See live code in IdeOne.com.
Note that LocalDateTime lacks any concept of time zone or offset-from-UTC. So this does not represent a moment on the timeline. Apply a zone or offset if you know one was intended. Already covered many times on Stack Overflow; search for OffsetDateTime and ZonedDateTime.
As for database and SQLite, there are many other Questions and Answers already handling this. Your JDBC 4.2 driver may handle conversion of java.time types directly. If not, store as string using standard ISO 8601 format.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and 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 SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
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 should work only with Date object instread of String. Format your date into string only when you whant to display it.
With a Date object you will be able to get the value in ms and do computation on it. You can also use Calendar to breakdown a date.
You should not work with String objects but Date instead. Only format date if and when you want to display it.
Date originalDate = new Date();
long diff = 60 * 1000; // milliseconds!
Date diffedDate = new Date(originalDate.getTime() - diff);
If you really want to do it the string way (which you should not), you can parse the date string like this:
String originalDateString = getDateTime(); // your current function
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date badlyDesignedOriginalDate = dateFormat.parse(originalDateString);
long diff = 60 * 1000; // milliseconds!
Date diffedDate = new Date(badlyDesignedOriginalDate.getTime() - diff);
But again, you should not do this.
You could use something like this:
long minute = 1000*60;
Date date1 = new Date(); //current date
Date date2 = new Date(date1.getTime() - minute); //new date, 1 minute older
//or another method
long minute = 1000*60;
Date date1 = new Date();
date1.setTime(date1.getTime() - minute);
Date works with milliseconds since January 1, 1970, 00:00:00 GMT, so you can substract it like normal numbers.

String to Date in Java

I have a date string like this "2010-12-10T20:03:53-06:00"
I want to convert the same into equivalent date object in Java.
Any Idea how to do this?
What you are looking for is SimpleDateFormat.parse(). It will convert a string into a Date object.
http://docs.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html
If you're using Java 7, you should be okay without any string massaging, using the new X specifier for the UTC offset:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX", Locale.US);
Date date = format.parse(text);
(Testing to make sure - when I've installed JDK 7 myself :)
In general I would strongly recommend using Joda Time for date handling, however. Its Z specifier can handle an offset with a colon:
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ")
.withLocale(Locale.US);
DateTime dateTime = formatter.parseDateTime(text);
In fact, there's an ISODateTimeFormat class to make this even simpler:
DateTimeFormatter formatter = ISODateTimeFormat.dateTimeNoMillis();
Joda Time is a significantly better date/time API than the built-in one. (It's far from perfect, but it's a lot better than Date and Calendar...)
You should use DateFormat class for this:
First you need to get rid of that : in the timezone part and make your date string like this
2010-12-10T20:03:53-0600
and use the code snippet below:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date d = formatter.parse("2010-12-10T20:03:53-0600");
Note: I checked this on Java 6 and Mr. Skeet has mentioned a better answer dealing with Java 7 as I don't know more about Java 7
Use Joda time. It is powerful and easy to use.
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.
Demo:
import java.time.OffsetDateTime;
public class Main {
public static void main(String[] args) {
OffsetDateTime odt = OffsetDateTime.parse("2010-12-10T20:03:53-06:00");
System.out.println(odt);
}
}
Output:
2010-12-10T20:03:53-06:00
ONLINE DEMO
For any reason, if you need to convert this object of OffsetDateTime to an object of java.util.Date, you can do so as follows:
Date date = Date.from(odt.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.
You can't parse a date with a colon in the time zone with the standard JDK Date until Java 7. Before Java 7 timezone would have to be either a full time zone with name or in the form -0600.
You have 3 options:
if you use Java 7+, use this pattern: "yyyy-MM-dd'T'HH:mm:ssX" with a SimpleDateFormat
manually remove the colon and parse
use Joda Time, for example: https://stackoverflow.com/a/2375539/829571
Here is an example with the second option:
public static void main(String[] args) throws ParseException {
String input = "2010-12-10T20:03:53-06:00";
int colon = input.lastIndexOf(":");
input = input.substring(0, colon) + input.substring(colon + 1, input.length());
System.out.println(input);
DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date date = fmt.parse(input);
System.out.println("date = " + date);
}

Categories