I have a question about converting from 12-hour am/pm format to 24-hour format. I have tried using SimpleDateFormat but encountered some problems.
As you can see, I printed 5 lines of original and converted time, but failed for cases ending with "PM". Note that some inputs are of the 24-hour format and others have the 12-hour am/pm format.
Below is the code I write for the conversion:
static String standardizeTime(String inputTime) throws ParseException {
SimpleDateFormat[] testInputFormat = new SimpleDateFormat[2];
SimpleDateFormat returnFormat = new SimpleDateFormat("HH:mm");
testInputFormat[0] = new SimpleDateFormat("hh:mm aa");
testInputFormat[1] = new SimpleDateFormat("HH:mm");
testInputFormat[0].setLenient(false);
testInputFormat[1].setLenient(false);
Date time;
for (int i = 0; i < testInputFormat.length; i++) {
try {
time = testInputFormat[i].parse(inputTime);
return returnFormat.format(time);
} catch (ParseException e) {
continue;
}
}
return "";
}
What should I change to fix this problem?
This works as expected.
import java.text.SimpleDateFormat;
public class HelloWorld{
public static void main(String []args) throws Exception {
final SimpleDateFormat parser = new SimpleDateFormat("hh:mm aa");
final SimpleDateFormat printer = new SimpleDateFormat("HH:mm");
System.out.println(printer.format(parser.parse("4:07 pm")));
}
}
Your code looks good so I think problem is elsewhere.
I fixed my problem by referring to this post: java.text.ParseException: Unparseable date
The problem is, the default language of my computer is not English, so take Alexander's response as an example. I need to write:
import java.text.SimpleDateFormat;
import java.util.Locale;
public class HelloWorld{
public static void main(String []args) throws Exception {
final SimpleDateFormat parser = new SimpleDateFormat("hh:mm aa", Locale.ENGLISH);
final SimpleDateFormat printer = new SimpleDateFormat("HH:mm");
System.out.println(printer.format(parser.parse("4:07 pm")));
}
}
Note the "Locale.ENGLISH" in parser!
Make sure to use Locale with date/time formatting API whenever the date/time contains letters because different locales have a different representation of letters.
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 stfInput = new SimpleDateFormat("h:m a", Locale.ENGLISH);// 12-hour format
DateFormat stfOutput = new SimpleDateFormat("HH:mm", Locale.ENGLISH);// 24-hour format
Date time = stfInput.parse("02:57 AM");
System.out.println(stfOutput.format(time));
time = stfInput.parse("07:05 PM");
System.out.println(stfOutput.format(time));
}
}
Output:
02:57
19:05
Note: java.util date-time classes are outdated and error-prone and so is their formatting API, SimpleDateFormat. I suggest you should stop using them completely and switch to the modern date-time API. 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.
Using the modern date-time API:
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("h:m a", Locale.ENGLISH);// 12-hour format
DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("HH:mm", Locale.ENGLISH);// 24-hour format
LocalTime time = LocalTime.parse("02:57 AM", dtfInput);
System.out.println(time.format(dtfOutput));
time = LocalTime.parse("07:05 PM", dtfInput);
System.out.println(time.format(dtfOutput));
}
}
Output:
02:57
19:05
What should I change to fix this problem?
First and most importantly: I recommend that you use java.time, the modern Java date and time API, for your time work. The date-time classes that you tried to use, SimpleDateFormat and Date, are poorly designed and long outdated. The modern API is so much nicer to work with. The last half of the answer by Arvind Kumar Avinash shows you how. There is no reason for me to repeat it. And yes, Arvind’s code does fix your problem.
What went wrong in your code?
It’s been said that your problem is not providing an English-speaking locale to your formatter. This is part of the truth, but it doesn’t fully explain why 07:05 PM was converted to 07:05 where the correct conversion would have given 19:05.
What happened was that your first input formatter, the one with pattern hh:mm aa, failed at parsing because it used a language where PM would be called something else. Next the second formatter, with pattern HH:mm succeeded in parsing the string. Surprising, isn’t it? I consider it one of the many confusing traits of SimpleDateFormat that it doesn’t necessarily parse the entire string. It parsed the 07:05 part as hour of day and minute. Then it ignored the remainder of the string. In this way you got the result 07:05, which is incorrect, instead of the correct 19:05. This is just one of the reasons why you shouldn’t use SimpleDateFormat at all.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Related questions:
Java SimpleDateFormat throwing ParseException: Unparseable date on Windows but not on Mac [duplicate] about locale for parsing AM an PM. I obviously recommend the answer by Basil Bourque using java.time.
SimpleDateFormat parse(string str) doesn't throw an exception when str = 2011/12/12aaaaaaaaa? about SimpleDateFormat not parsing the entire string. Be inspired by the answer by David using java.time to solve the problem in an easy and straightforward way.
Force SimpleDateFormat to parse the whole string, which seems to me to be similar to yours.
Conversion from 12 hours time to 24 hours time in java. I recommend the answer by Cloud using java.time.
Related
This question already has answers here:
Java: getTimeZone without returning a default value
(5 answers)
Strange Java Timezone Date Conversion Problem
(3 answers)
Closed 2 years ago.
I have a given string 06/17/2008T13:53:23Z, I want to convert that to EDT time zone. So my output will be 6/17/08 9:53 AM EDT.
Below is my Java Code, it is giving wrong output:
SimpleDateFormat format1 = new SimpleDateFormat("MM/dd/yyyy'T'hh:mm:ss'Z'");
SimpleDateFormat format2 = new SimpleDateFormat("M/d/yy hh:mm a");
format1.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = format1.parse("06/17/2008T13:53:23Z");
System.out.println(date);
format2.setTimeZone(TimeZone.getTimeZone("EDT"));
System.out.println(format2.format(date));
It gives output as :
Tue Jun 17 19:23:23 IST 2008
6/17/08 01:53 PM
Here the output time as 01:53 PM instead of 9:53 AM EDT
How to fix this issue?
Your parsing pattern uses hh (which is for 12-hour format) whereas the time in your date-time string is in 24-hour format for which you need to use HH. Secondly, you should avoid using the three-letter time-zone name. As you have already expected, EDT has a Zone-Offset of -4 hours and you can use this as GMT-4 with SimpleDateFormat.
While a Zone-Offset is expressed in terms of numbers (hours, minutes or seconds), a timezone is expressed as a string representing the name (e.g. America/New_York) of the timezone. The relation between timezone and Zone-Offset is many-to-one i.e. many timezones can have the same Zone-Offset.
Note that java.util date-time classes are outdated and error-prone and so is their formatting API, SimpleDateFormat. I suggest you should stop using them completely and switch to the modern date-time API. 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.
Using the modern date-time API:
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
String str = "06/17/2008T13:53:23Z";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/u'T'H:m:sz");
ZonedDateTime zdt = ZonedDateTime.parse(str, formatter);
// Convert to Eastern Time
ZonedDateTime zdtET = zdt.withZoneSameInstant(ZoneId.of("America/New_York"));
// ZonedDateTime zdtET = zdt.withZoneSameInstant(ZoneOffset.ofHours(-4));// Or this
// Print in default format i.e. ZonedDateTime#toString
System.out.println(zdtET);
// Print in custom formats
System.out.println(zdtET.format(DateTimeFormatter.ofPattern("MM/dd/uuuu'T'HH:mm:ss zzzz")));
System.out.println(zdtET.format(DateTimeFormatter.ofPattern("M/d/uu hh:mm:ss a")));
}
}
Output:
2008-06-17T09:53:23-04:00[America/New_York]
06/17/2008T09:53:23 Eastern Daylight Time
6/17/08 09:53:23 am
Note: If you use ZoneOffset.ofHours(-4) [commented in the code above], you can not get the name of timezone (e.g. America/New_York) in the output because, as explained earlier, many timezones can have the same Zone-Offset and there is no default timezone for a Zone-Offset.
Using the legacy API:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
String str = "06/17/2008T13:53:23Z";
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy'T'HH:mm:ss");
formatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
Date date = formatter.parse(str);
// Convert to Eastern Time
SimpleDateFormat sdfOutput = new SimpleDateFormat("M/d/yy hh:mm a");
sdfOutput.setTimeZone(TimeZone.getTimeZone("America/New_York"));
// sdfOutput.setTimeZone(TimeZone.getTimeZone("GMT-4"));// Or this
System.out.println(sdfOutput.format(date));
}
}
Output:
6/17/08 09:53 am
This question already has answers here:
Java SimpleDateFormat Timezone offset with minute separated by colon
(2 answers)
Closed 3 years ago.
I'm using java's SimpleDateFormat, here is my code:
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZ");
String strDate = simpleDateFormat.format(date);
System.out.println(strDate);
Which print out:
2019-11-15T11:59:47.289+0200
But, I want to have a colon inside the offset, which means it need to look like this:
2019-11-15T11:59:47.289+02:00
Is there a way to adding a time zone that printed out like the second example here?
What you are talking about is not a time zone (like UTC), it is an offset (like +01:00).
You can use the modern date time API java.time, which has a built-in DateTimeFormatter.ISO_OFFSET_DATE_TIME, that formats the offset as desired:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
public class StackoverflowDemo {
public static void main(String[] args) {
OffsetDateTime odt = OffsetDateTime.now();
System.out.println(odt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
}
}
The output on my system is this:
2019-11-15T11:30:46.532+01:00
this snippet below gives result like this
2019-11-15T16:03:53+05:30
SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
System.out.println(dateFormat2.format(new Date()));
hope this is what you are looking for
Your format should be yyyy-MM-dd'T'hh:mm:ss.SSSXXX
I think your best bet is to use DateTimeFormatter.
You can find documentation here:
https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
I am getting a date string as 2014-01-11-T00:00:00Z
I want to convert this date to 20140111 i.e YYYYMMDD it should be a string.
Any standard method/function to achieve above?
java.time
Your date-time string, 2014-01-11-T00:00:00Z is a bit weird as I have never seen such a date-time string where there is a hyphen (-) before T. For this kind of string, the following pattern meets the parsing requirement:
yyyy-M-d-'T'H:m:sXXX
Also, with java.time API, I recommend you replace y with u as explained in this answer. For the output string, you do NOT need to define any pattern as there already exists an inbuilt DateTimeFormatter for this pattern: DateTimeFormatter.BASIC_ISO_DATE.
Demo:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String args[]) {
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("u-M-d-'T'H:m:sXXX", Locale.ENGLISH);
OffsetDateTime odt = OffsetDateTime.parse("2014-01-11-T00:00:00Z", dtfInput);
System.out.println(odt);
String output = odt.toLocalDate().format(DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(output);
}
}
Output:
2014-01-11T00:00Z
20140111
Note:
Had your date-time string been ISO 8601 compliant, you would NOT have needed to use a DateTimeFormatter object explicitly for parsing i.e. you could have simply parsed it as
OffsetDateTime odt = OffsetDateTime.parse("2014-01-11T00:00:00Z");
The Z in the date-time stands for Zulu which specifies UTC time (that has a timezone offset of +00:00 hours) in ISO 8601 standard. Thus, this solution will also work for a date-time string like 2014-01-11-T00:00:00+02:00 which has a timezone offset of +02:00 hours.
In case, you need a java.util.Date object from this object of OffsetDateTime, you can do so as follows:
Date date = Date.from(odt.toInstant());
Learn more about the the modern date-time API* from Trail: Date Time.
Note that the legacy date-time API (java.util date-time types and their formatting API, SimpleDateFormat) are outdated and error-prone. It is recommended to stop using them completely and switch to java.time API. Just for the sake of completeness, I am providing you with a solution using the legacy API.
Using the legacy API:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String args[]) throws ParseException {
SimpleDateFormat sdfInput = new SimpleDateFormat("yyyy-M-d-'T'H:m:sXXX", Locale.ENGLISH);
SimpleDateFormat sdfOutput = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH);
sdfOutput.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));// Change it as required
Date date = sdfInput.parse("2014-01-11-T00:00:00Z");
String output = sdfOutput.format(date);
System.out.println(output);
}
}
Output:
20140111
* 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.
Take this
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateFormat {
public static void main(String[] args) throws ParseException {
SimpleDateFormat inFormat = new SimpleDateFormat("yyyy-MM-dd-'T'HH:mm:ss'Z'");
Date inDate = inFormat.parse("2014-01-11-T00:00:00Z");
SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMdd");
String output = outFormat.format(inDate);
System.out.println("Date: " + output);
}
}
Take a look at this thread for Date formatting in Java using Zoulou notation :
Converting ISO 8601-compliant String to java.util.Date
Then create a new SimpleDateFormat using the "yyyyMMdd" format string.
Here an improved version of given answer by #drkunibar:
SimpleDateFormat inFormat = new SimpleDateFormat("yyyy-MM-dd-'T'HH:mm:ss'Z'");
inFormat.setTimeZone(TimeZone.getTimeZone("GMT")); // Z denotes UTC in ISO-8601
Date inDate = inFormat.parse("2014-01-11-T00:00:00Z");
SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMdd");
outFormat.setTimeZone(TimeZone.getTimeZone("...")); // set your timezone explicitly!
String output = outFormat.format(inDate);
System.out.println("Date: " + output);
Note that the format YYYYMMDD is also ISO-8601-compliant (a so-called basic calendar date). The question you have to ask yourself is in which timezone you want to get your output. If in UTC you have to set "GMT", too. Without setting timezone it can happen that your output date differs from input UTC date by one day dependent where your default system timezone is (for example US is several hours behind UTC, in this case one calendar day before UTC midnight).
Update: This Answer is now obsolete. See the modern solution using java.time in the Answer by Avinash.
Joda-Time
This date-time work is much easier with the Joda-Time 2.3 library.
String input = "2014-01-11T00:00:00Z"; // In standard ISO 8601 format.
DateTime dateTime = new DateTime( input, DateTimeZone.UTC ); // Parse string into date-time object.
DateTimeFormatter formatter = ISODateTimeFormat.basicDate(); // Factory to make a formatter.
String output = formatter.print( dateTime ); // Generate string from date-Time object.
I am trying to validate a string whether it is in ISO-8601 date or not, but it is throwing a parse exception, not sure where it is going wrong.
try {
String s = "2007-03-01T13:00:00Z";
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
ft.setLenient(false);
System.out.println(ft.format(ft.parse(s)));
} catch (ParseException e) {
System.out.println(e.getMessage());
}
output is:
Unparseable date: "2007-03-01T10:00:00Z"
I suspect that Z is being interpreted as a time zone so would match -0800 but not a literal Z so you could solve that by quoting: 'Z'.
getErrorOffset should tell you where the problem is.
If you're using Java 7, use the following format string: "yyyy-MM-dd'T'HH:mm:ssXXX"
Note: X is a new code (added in Java 7) that matches ISO 8601 time zone strings; see the API documentation of SimpleDateFormat.
If you want to validate an arbitrary string, you cannot hardcode the "Z" time zone designator, as the validation would fail for a valid ISO8601 time stamp like e.g. "2007-03-01T13:00:00+01".
If you are using Java 6 or earlier, SimpleDateFormat will not support ISO8601 time zone encoding, so you cannot use it to validate time stamps either. With Java 7 or later, you can use new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");.
Your code does not work because the SDF is very limited ad was not aware of ISO 8601 at the time when it was written.
You can take this code:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.lang.time.DateUtils;
public final class JSONDateUtil {
private static final DateFormat ISO8601_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
static {
ISO8601_FORMAT.setLenient(false);
ISO8601_FORMAT.setTimeZone(DateUtils.UTC_TIME_ZONE);
}
public static String toJSON(Date date) {
return ISO8601_FORMAT.format(date);
}
public static String toJSON(long millis) {
return ISO8601_FORMAT.format(millis);
}
public static Date toJava(String date) {
try {
return ISO8601_FORMAT.parse(date);
} catch (ParseException e) {
return null;
}
}
}
Note the timezone, very important.
Joda-Time
FYI, if you used Joda-Time instead of the notoriously troublesome java.util.Date/Calendar classes, you could simply pass that ISO 8601 string straight into a DateTime constructor without the bother of a formatter. Joda-Time uses ISO 8601 as its defaults.
DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );
DateTime dateTime = new DateTime( "2007-03-01T13:00:00Z", timeZone );
Validation
To determine if your input string was invalid, catch IllegalArgumentException.
java.util.Date
You can even get a java.util.Date back out if need be.
java.util.Date date = dateTime.toDate();
I have a date format as "Nov 10,1980" in a string format(String str="Nov 10, 1980"), and i want to convert it to 1980-11-10. can any one tell me how to do that using java.
Thanks in advance
You should first parse it from the original text format, then format the result using the format you want it to end up as. You can use SimpleDateFormat for this, or Joda Time (which is generally a much better date/time API).
Sample code using SimpleDateFormat:
import java.text.*;
import java.util.*;
public class Test {
public static void main(String[] args) throws Exception {
String inputText = "Nov 10,1980";
TimeZone utc = TimeZone.getTimeZone("UTC");
// Or dd instead of d - it depends whether you'd use "Nov 08,1980"
// or "Nov 8,1980" etc.
SimpleDateFormat inputFormat = new SimpleDateFormat("MMM d,yyyy",
Locale.US);
inputFormat.setTimeZone(utc);
SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd",
Locale.US);
outputFormat.setTimeZone(utc);
Date parsed = inputFormat.parse(inputText);
String outputText = outputFormat.format(parsed);
System.out.println(outputText); // 1980-11-10
}
}
Note that:
I've explicitly specified the locale to use; otherwise if you try to parse the text on a system with (say) a French default locale, it will try to parse it using French month names.
I've explicitly set the time zone as UTC to avoid any daylight saving time issues (where a particular value could be ambiguous or even non-existent in the default time zone)
Use this
Date date = new Date();
SimpleDateFormat sdf;
sdf = new SimpleDateFormat("yyyy-MM-DD");
System.out.println(sdf.format(date));
try {
SimpleDateFormat sdf1 = new SimpleDateFormat("MMM dd, yyyy");
Date strDt = sdf1.parse("Nov 10, 1980");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(sdf2.format(strDt));
} catch (Exception e) {
e.printStackTrace();
}
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:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("MMM d,u", Locale.ENGLISH);
LocalDate date = LocalDate.parse("Nov 10,1980", dtfInput);
System.out.println(date);
}
}
Output:
1980-11-10
ONLINE DEMO
Notice that I have not used a DateTimeFormatter to format the LocalDate because your desired format is the same as the ISO 8601 format which is also the standard used for java.time API. Check the LocalDate#toString documentation for more details.
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.
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
String req_date = dateFormat.format(DATE)
System.out.println(req_date)
You can use two SimpleDateFormats. One to parse, one to format. For example:
public static void main(String[] args) throws ParseException {
DateFormat parseFormat = new SimpleDateFormat("MMM dd,yyyy");
DateFormat displayFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = parseFormat.parse("Nov 10,1980");
String s = displayFormat.format(date);
System.err.println(s);
}
Use the SimpleDateFormat to get the result you want