How to parse a ISO 8601 to Date in Java? - java

I'm trying to parse a ISO 8601 date to a Date object, but I can't.
I'm trying the following:
String date = "2021-05-14T09:26:20";
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd HH:MM:ss");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:MM:ss");
Date newDate = parser.parse(date);
System.out.println(format.format(newDate));
But I get this error:
Exception in thread "main" java.text.ParseException: Unparseable date: "2021-05-14T09:26:20"
at java.text.DateFormat.parse(DateFormat.java:366)
at com.pruebas.pruebas.fechas.main(fechas.java:14)
How can I solve this?

Problems with your code:
The pattern for parsing should match with the given date-time string. You have missed 'T' in the pattern for parsing.
Also, you have used M instead of m for "Minute in hour". The symbol, M is used for "Month in year". Read the documentation carefully.
Demo with correct patterns:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
public static void main(String[] args) throws ParseException {
String date = "2021-05-14T09:26:20";
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date newDate = parser.parse(date);
System.out.println(format.format(newDate));
}
}
ONLINE DEMO
Introducing java.time, the modern Date-Time API:
Note that 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*, released in March 2014 as part of Java SE 8 standard library.
Solution using java.time, the modern Date-Time API:
The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards.
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String date = "2021-05-14T09:26:20";
LocalDateTime ldt = LocalDateTime.parse(date);
System.out.println(ldt);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH);
System.out.println(dtf.format(ldt));
}
}
Output:
2021-05-14T09:26:20
2023-02-14 09:02:20
ONLINE DEMO
Here, you can use y instead of u but I prefer u to y.
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.

Though #Arvind gave some good explanations and examples your issue in this particular instance is simply a typo. The string:
String date = "2021-05-14T09:26:20";
includes a T literal to separate the date from the time as per the ISO-8601 standard. You have simply forgotten this in your SimpleDateFormat:
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd HH:MM:ss");
You should have this:
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
And all should work.

Related

get the day of the year as an integer in Kotlin Android Studio

I am trying to get the current day of the year as an integer to access within my program. I looked at the Kotlin Docs and found a function called getDay(), but when I type it into my program it gives me an error and says the function is not defined. I am using Android Studio with Kotlin and the minimum API is 21.
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Note: If you want to work with a specific timezone, use LocalDate.now(ZoneId)
// e.g. LocalDate.now(ZoneId.of("Australia/Brisbane")) or
// LocalDate.now(ZoneOffset.UTC) etc.
LocalDate today = LocalDate.now();
int doy = today.getDayOfYear();
System.out.println(doy);
// Using DateTimeFormatter (not recommended for production code)
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("D", Locale.ENGLISH);
String strDoy = today.format(dtf);
System.out.println(strDoy);
}
}
Output in my timezone, Europe/London:
289
289
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
For any reason, if you want to use the legacy API:
A java.util.Date object simply represents an instant on the timeline — a wrapper around the number of milliseconds since the UNIX epoch (January 1, 1970, 00:00:00 GMT). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone e.g.
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String strDateNewYork = sdf.format(date);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String strDateUtc = sdf.format(date);
Let's see why knowing the above fact is important:
The function, Calendar#getInstance returns a calendar based on the current time in the default time zone with the default FORMAT locale. If you want to find some information from it for some other timezone, you have two options:
Change the default timezone e.g. TimeZone.setDefault(TimeZone.getTimeZone("Australia/Brisbane")). However, this may result in other parts of the application behave incorrectly. Therefore, this option is strongly discouraged.
Format the java.util.Date (which you can get via Calendar#getTime) using SimpleDateFormat set with the required timezone shown above.
Demo:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("D");
// For the JVM's timezone
sdf.setTimeZone(TimeZone.getDefault());
System.out.println(sdf.format(now));
// For the timezone, UTC
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(sdf.format(now));
// For the timezone, Australia/Brisbane
sdf.setTimeZone(TimeZone.getTimeZone("Australia/Brisbane"));
System.out.println(sdf.format(now));
System.out.println();
}
}
Output in my timezone, Europe/London at the time of posting this answer:
289
289
290
ONLINE DEMO
* 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. Note that Android 8.0 Oreo already provides support for java.time.
If you perform desugaring in order to be able to use Java 8 Time API back to API 21, you can then use this method to get the day of year
import java.time.LocalDate
val dayOfYear = LocalDate.now().dayOfYear
System.out.println(dayOfYear);
Answer: 289
Date().getDay() or rather Date().day in Kotlin returns the day of the week so not what you want.
Calendar.getInstance().get(Calendar.DAY_OF_YEAR) is the correct function to use in Android. It returns a calendar using the default time zone and locale. The Calendar returned is based on the current time in the default time zone with the default FORMAT locale (https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--).
Calendar, Date etc. have been replaced by new java.time classes with Java 8 so you should use LocalDate.now().dayOfYear but as #nuhkoca indicates in order to do that you need to enable Java 8+ API desugaring support which is basically adding this to your build file (Kotlin DSL not Groovy):
compileOptions {
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5")
try this code :
import java.time.LocalDate
import java.util.*
fun main() {
val cal = Calendar.getInstance()
val day = cal[Calendar.DATE]
val doy = cal[Calendar.DAY_OF_YEAR]
println("Current Date: " + cal.time)
println("Day : $day")
println("Day of Year : $doy")
}

How to resolve Unparseable date Exception in Java 8 with Date format yyyy-MM-dd hh:mm a

I have a text file from which I am reading and setting transaction POJO class data, to get the difference between start and end time I need to parse the time information in date object.
DateFormat format = new SimpleDateFormat(dateFormat);
System.out.println("Date format in play:"+dateFormat);
Transaction transaction = storageRepositroy.getTransaction(key);
Date start = format.parse(transaction.getStartDate() + " " + transaction.getStartTime());//line no. 29
Date end = format.parse(transaction.getEndDate() + " " + transaction.getEndTime());
I am getting exception while running this code
Exception is
Date format in play:yyyy-MM-dd hh:mm a
java.text.ParseException: Unparseable date: "2020–03–01 03:15 PM"
at java.text.DateFormat.parse(DateFormat.java:366)
at dc.tech.transaction.util.TimeUtil.calculateAverageTime(TimeUtil.java:29)
yyyy-MM-dd hh:mm a is the date format which I am passing to SimleDateFormat constructor. I am unable to understand and debug why I am getting this error.
java.time
I recommend that you use java.time, the modern Java date and time API, for your date and time work.
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuu\u2013MM\u2013dd");
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm a", Locale.ENGLISH);
String dateString = "2020–03–01";
String timeString = "03:15 PM";
LocalDate date = LocalDate.parse(dateString, dateFormatter);
LocalTime time = LocalTime.parse(timeString, timeFormatter);
LocalDateTime dateTime = date.atTime(time);
System.out.println(dateTime);
Output:
2020-03-01T15:15
With java.time it is straightforward to combine date and time after parsing, so I prefer to parse them individually.
What went wrong in your code?
Credits go to Ajeetkumar for noticing and reporting in comments: The hyphen in your date string is not a usual minus sign or hyphen with character value 2D hexadecimal (45 decimal), but a en dash with character value 2013 hexadecimal (8211 decimal). So when you specify a usual hyphen in your format pattern string, they don’t match, and parsing fails. Instead I am using a Unicode escape for putting the en dash into the format pattern string. Simply pasting it in there would have worked too (provided that you save your .java file with a character encoding that supports it), but I wanted to make the reader aware that something special was going on here, so I preferred the Unicode escape with \u.
There is another problem with your code: You are not providing any locale for your formatter. So it uses the default locale of your JVM. As long as that locale expects PM, parsing will work. If one day you change your locale setting or run your code on a computer or JVM with a different default locale, parsing will suddenly fail, at you may have a hard time figuring out why. I have specified English locale for parsing the time. Some would prefer doing it for the date too even though technically it isn’t necessary.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Unicode Character 'EN DASH' (U+2013) on FileFormat.info.
I always stick to this mantra: use exactly the same format as your date-time string.
In the solutions given below, I have copied your date-time string into the pattern that I've specified for SimpleDateFormat and DateTimeFormatter and replaced the numbers with the corresponding letters e.g. 2020 with yyyy while keeping the rest of things (symbols, space etc.) intact.
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
DateFormat sdf = new SimpleDateFormat("yyyy–MM–dd hh:mm a", Locale.ENGLISH);// Make sure to use Locale
String dateTimeString = "2020–03–01 03:15 PM";// The string copied from the exception you have got
Date date = sdf.parse(dateTimeString);
System.out.println(sdf.format(date));
}
}
Output:
2020–03–01 03:15 PM
Note: The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. I suggest you should stop using them completely and switch to the modern date-time API.
Using the modern date-time API:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy–MM–dd hh:mm a", Locale.ENGLISH);// Make sure to use Locale
String dateTimeString = "2020–03–01 03:15 PM";// The string copied from the exception you have got
System.out.println(LocalDateTime.parse(dateTimeString, dtf));
}
}
Output:
2020-03-01T15:15
Learn more about the modern date-time API at Trail: Date Time.
If you are doing it for your 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.

Converting epoch time stamp to readable date not working

I'm trying to use this code to convert the timestamp i have but the output is completely wrong, the output is 17/01/1970 16:56:28!!! it should be 8/7/2014 5:14:59 PM
Date date = new Date(1407388499);
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String formatted = format.format(date);
System.out.println(formatted);
format.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
formatted = format.format(date);
System.out.println(formatted);
Help me please
Your date is not long enough
new Date(1407388499);
Sat Jan 17 1970 15:56:28 GMT+0900 (Japan Standard Time)
new Date(1407388499000);
Thu Aug 07 2014 14:14:59 GMT+0900 (Japan Standard Time)
The value should be a Long that is the number of millseconds
Edit
So if your received number is
int dt = 1407388499:
Then you need to do
Date date = new Date(1000L * dt);
java.time
The root cause of the problem is that the Unix time specifies seconds since the Epoch whereas java.util.Date(long date) expects the number of milliseconds since the Epoch. So, you need to convert the Unix time into milliseconds and then pass the same to java.util.Date(long date).
However, the legacy date-time API (java.util date-time types and their formatting type, SimpleDateFormat etc.) is outdated and error-prone. It is recommended to stop using it completely and switch to java.time, the modern date-time API*.
Solution using java.time, the modern API:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.ofEpochSecond(1407388499);
// Corresponding date-time in Australia/Sydney
ZonedDateTime zdtSydney = instant.atZone(ZoneId.of("Australia/Sydney"));
System.out.println(zdtSydney);
// Formatted
System.out.println(DateTimeFormatter.ofPattern("dd/MM/uuuu HH:mm:ss", Locale.ENGLISH).format(zdtSydney));
}
}
Output:
2014-08-07T15:14:59+10:00[Australia/Sydney]
07/08/2014 15:14:59
Learn more about java.time, the modern date-time API* from Trail: Date Time.
Solution using the legacy API:
Avoid performing calculations yourself if there is an OOTB (Out-Of-The-Box) API available for it e.g. TimeUnit#convert.
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
Date date = new Date(TimeUnit.MILLISECONDS.convert(1407388499, TimeUnit.SECONDS));
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
System.out.println(format.format(date));
}
}
Output:
07/08/2014 15:14:59
* 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.

Generating UTC Time in java

I want to get the UTC time for 01/01/2100 in Java to '2100-01-01 00:00:00'. I am getting "2100-01-01 00:08:00". Any idea, how to correct this.
public Date getFinalTime() {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
Date finalTime = null;
try
{
finalTime = df.parse("01/01/2100");
} catch (ParseException e)
{
e.printStackTrace();
}
calendar.setTime(finalTime);
return calendar.getTime();
}
You need to specify the time zone for the SimpleDateFormat as well - currently that's parsing midnight local time which is ending up as 8am UTC.
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar calendar = Calendar.getInstance(utc);
DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
df.setTimeZone(utc);
Date finalTime = null;
try
{
finalTime = df.parse("01/01/2100");
} catch (ParseException e)
{
e.printStackTrace();
}
calendar.setTime(finalTime);
As ever though, I would personally recommend using Joda Time which is far more capable in general. I'd be happy to translate your example into Joda Time if you want.
Additionally, I see you're returning calendar.getTime() - that's just the same as returning finalTime as soon as you've computed it.
Finally, just catching a ParseException and carrying on as if it didn't happen is a very bad idea. I'm hoping this is just sample code and it doesn't reflect your real method. Likewise I'm assuming that really you'll be parsing some other text - if you're not, then as Eyal said, you should just call methods on Calendar directly. (Or, again, use Joda Time.)
You need to set the time zone of the SimpleDateFormat object as well, otherwise it assumes the default time zone.
Anyway, it seems like using only a Calendar is enough in your case. Use its setters to set the right values for all fields (year, month, day, hour, etc), and then retrieve the 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 at 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 API:
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDate = "01/01/2100";
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("d/M/u", Locale.ENGLISH);
ZonedDateTime zdt = LocalDate.parse(strDate, dtfInput)
.atStartOfDay(ZoneId.of("Etc/UTC"));
// Default format
System.out.println(zdt);
// Getting and displaying LocalDateTime
LocalDateTime ldt = zdt.toLocalDateTime();
System.out.println(ldt);
// A custom format
DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH);
// Alternatively dtfOutput.format(ldt);
String formatted = dtfOutput.format(zdt);
System.out.println(formatted);
// Converting to some other types
OffsetDateTime odt = zdt.toOffsetDateTime();
Instant instant = zdt.toInstant();
System.out.println(odt);
System.out.println(instant);
}
}
Output:
2100-01-01T00:00Z[Etc/UTC]
2100-01-01T00:00
2100-01-01 00:00:00
2100-01-01T00:00Z
2100-01-01T00:00:00Z
ONLINE DEMO
The Z in the output is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
Note: The Date-Time without timezone name or timezone offset should be represented by LocalDateTime (which is used for events that are normally not represented with timezone information). In this sense, LocalDateTime is useless in this case and you should use ZonedDateTime itself or Instant or OffsetDateTime. I recommend you also check this answer and this answer if you are dealing with JDBC.
Learn more about java.time, 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.
java.time
Like Arvind Kumar Avinash I very clearly recommend that you use java.time, the modern Java date and time API, for your date and time work. If what you want is a fixed (constant) date and time, use OffsetDateTime.of().
OffsetDateTime finalTime = OffsetDateTime.of(2100, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC);
System.out.println(finalTime);
Output:
2100-01-01T00:00Z
The trailing Z means UTC.
Tutorial link
Oracle tutorial: Date Time explaining how to use java.time.
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar calendar = Calendar.getInstance(utc);
DateFormat dateformat = new SimpleDateFormat("dd/MM/yyyy");
dateformat.setTimeZone(utc);
Timezone needs to be set.

Output RFC 3339 Timestamp in Java

I want to output a timestamp with a PST offset (e.g., 2008-11-13T13:23:30-08:00). java.util.SimpleDateFormat does not seem to output timezone offsets in the hour:minute format, it excludes the colon. Is there a simple way to get that timestamp in Java?
// I want 2008-11-13T12:23:30-08:00
String timestamp = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").format(new Date());
System.out.println(timestamp);
// prints "2008-11-13T12:23:30-0800" See the difference?
Also, SimpleDateFormat cannot properly parse the example above. It throws a ParseException.
// Throws a ParseException
new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").parse("2008-11-13T13:23:30-08:00")
Starting in Java 7, there's the X pattern string for ISO8601 time zone. For strings in the format you describe, use XXX. See the documentation.
Sample:
System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX")
.format(new Date()));
Result:
2014-03-31T14:11:29+02:00
Check out the Joda Time package. They make RFC 3339 date formatting a lot easier.
Joda Example:
DateTime dt = new DateTime(2011,1,2,12,45,0,0, DateTimeZone.UTC);
DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
String outRfc = fmt.print(dt);
From the "get it done dept," one solution is to use regexes to fix up the string after SimpleDateFormat has completed. Something like s/(\d{2})(\d{2})$/$1:$2/ in Perl.
If you are even remotely interested in this, I will edit this response with the working Java code.
But, yeah. I am hitting this problem too. RFC3339, I'm looking at you!
EDIT:
This works for me
// As a private class member
private SimpleDateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
String toRFC3339(Date d)
{
return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2");
}
I spent quite a lot of time looking for an answer to the same issue and I found something here : http://developer.android.com/reference/java/text/SimpleDateFormat.html
Suggested answer:
String timestamp = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZZZZZ").format(new Date());
If you notice I am using 5 'Z' instead of one. This gives the output with a colon in the offset like this: "2008-11-13T12:23:30-08:00". Hope it helps.
The problem is that Z produces the time zone offset without a colon (:) as the separator.
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ss.SZ");
Is not what exactly you need?
We can simply use ZonedDateTime class and DateTimeFormatter class for this.
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx");
ZonedDateTime z2 = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS);
System.out.println("format =======> " + z2.format(format));
Output: format =======> 30-03-2020T05:57:37+00:00
I found a stray PasteBin that helped me out with the issue: http://pastebin.com/y3TCAikc
Just in case its contents later get deleted:
// I want 2008-11-13T12:23:30-08:00
String timestamp = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").format(new Date());
System.out.println(timestamp);
// prints "2008-11-13T12:23:30-0800" See the difference?
// Throws a ParseException
new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").parse("2008-11-13T13:23:30-08:00")
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ss.SZ");
I made a InternetDateFormat class for RFC3339.
But source code comment is Japanese.
PS:I created English edition and refactoring a little.
i tried this format and worked for me yyyy-MM-dd'T'HH:mm:ss'Z'
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 largest city in the Pacific Time Zone is Los Angeles whose timezone name is America/Los_Angeles. Using ZoneId.of("America/Los_Angeles"), you can create an instance of ZonedDateTime which has been designed to adjust the timezone offset automatically on DST transitions.
If you need timezone offset but not the timezone name, you can convert a ZonedDateTime into OffsetDateTime using ZonedDateTime#toOffsetDateTime. Some other uses of OffsetDateTime are to create a Date-Time instance with a fixed timezone offset (e.g. Instant.now().atOffset(ZoneOffset.of("+05:30")), and to parse a Date-Time string with timezone offset.
Demo:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String[] args) {
ZoneId zoneIdLosAngeles = ZoneId.of("America/Los_Angeles");
ZonedDateTime zdtNowLosAngeles = ZonedDateTime.now(zoneIdLosAngeles);
System.out.println(zdtNowLosAngeles);
// With zone offset but without time zone name
OffsetDateTime odtNowLosAngeles = zdtNowLosAngeles.toOffsetDateTime();
System.out.println(odtNowLosAngeles);
// Truncated up to seconds
odtNowLosAngeles = odtNowLosAngeles.truncatedTo(ChronoUnit.SECONDS);
System.out.println(odtNowLosAngeles);
// ################ A winter date-time ################
ZonedDateTime zdtLosAngelesWinter = ZonedDateTime
.of(LocalDateTime.of(LocalDate.of(2021, 11, 20), LocalTime.of(10, 20)), zoneIdLosAngeles);
System.out.println(zdtLosAngelesWinter); // 2021-11-20T10:20-08:00[America/Los_Angeles]
System.out.println(zdtLosAngelesWinter.toOffsetDateTime()); // 2021-11-20T10:20-08:00
// ################ Parsing a date-time string with zone offset ################
String strDateTime = "2008-11-13T13:23:30-08:00";
OffsetDateTime odt = OffsetDateTime.parse(strDateTime);
System.out.println(odt); // 2008-11-13T13:23:30-08:00
}
}
Output from a sample run:
2021-07-18T03:27:15.578028-07:00[America/Los_Angeles]
2021-07-18T03:27:15.578028-07:00
2021-07-18T03:27:15-07:00
2021-11-20T10:20-08:00[America/Los_Angeles]
2021-11-20T10:20-08:00
2008-11-13T13:23:30-08:00
ONLINE DEMO
You must have noticed that I have not used a DateTimeFormatter to parse the Date-Time string of your question. It is because your Date-Time string is compliant with ISO-8601 standards. 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.
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.
I tested a lot with this one, works well for me... In particular when it comes to parsing (and for formatting too), it is the closest I have found so far
DateTimeFormatter rfc3339Formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
DateTimeFormatter rfc3339Parser = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendValue(ChronoField.YEAR, 4)
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH, 2)
.appendLiteral('T')
.appendValue(ChronoField.HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR, 2)
.appendLiteral(':')
.appendValue(ChronoField.SECOND_OF_MINUTE, 2)
.optionalStart()
.appendFraction(ChronoField.NANO_OF_SECOND, 2, 9, true) //2nd parameter: 2 for JRE (8, 11 LTS), 1 for JRE (17 LTS)
.optionalEnd()
.appendOffset("+HH:MM","Z")
.toFormatter()
.withResolverStyle(ResolverStyle.STRICT)
.withChronology(IsoChronology.INSTANCE);
Test cases at https://github.com/guyplusplus/RFC3339-DateTimeFormatter

Categories