Need to print the date exactly as "9999-99-99" using xmlgregoriancalendar type.
When i pass "9999-99-99" i get wrong output: 10007-07-08. How do i get output exactly as 9999-99-99
import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeFactory;
public class XMLGregorianCalendar {
public static void main(String[] args) {
/* Create Date Object */
//Date date = new Date();
javax.xml.datatype.XMLGregorianCalendar xmlDate = null;
//GregorianCalendar gc = new GregorianCalendar(2001,12,12);
GregorianCalendar gc = new GregorianCalendar(9999,99,99);
// gc.setTime(date);
try{
xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("XMLGregorianCalendar :- " + xmlDate);
}
}
Don’t
The XMLGregorianCalendar class was for dates and/or times for XML documents. Assuming that this was also your purpose, you must not put 9999-99-99 there. It’s not a valid date according to XML rules. Quoting XML Schema Part 2: Datatypes Second Edition, appendix D ISO 8601 Date and Time Formats:
M -- represents a digit used in the time element "month". The two digits in a MM format can have values from 1 to 12.
D -- represents a digit used in the time element "day". The two digits in a DD format can have values from 1 to 28 if the month value
equals 2, 1 to 29 if the month value equals 2 and the year is a leap
year, 1 to 30 if the month value equals 4, 6, 9 or 11, and 1 to 31 if
the month value equals 1, 3, 5, 7, 8, 10 or 12.
I have taken it out of context, but I think that we should understand that dates in XML documents need to be valid dates. 9999-99-99 is not a valid date since there is no month 99 and no month has 99 days in it.
If you wanted 9999-99-99 for something else than an XML document, I don’t think you should be using XMLGregorianCalendar at all. Without context I dare not suggest alternatives.
java.time I said “was … for XML documents”. Dates and times in XML documents are inspired from ISO 8601 formats and close enough that we usually can use the classes from java.time, the modern Java date and time API rather than XMLGregorianCalendar for them and still get the correct syntax from the toString methods of those classes. So also for valid dates consider using the modern LocalDate from java.time rather than the old XMLGregorianCalendar.
You cannot
XMLGregorianCalendar imposes the restriction of a valid date, so cannot print 9999-99-99.
What happened in your code was that GregorianCalendar tacitly and confusingly modified the date into a valid one. Try for example:
GregorianCalendar gc = new GregorianCalendar(9999,99,99);
System.out.println(gc.getTime());
On my computer I got:
Sun Jul 08 00:00:00 CEST 10007
When given invalid month and day of month, GregorianCalendar just keeps counting months and days into the following years. Since 99 months is a little more than 8 years, we end up more than 8 years after January 9999, and a further 3 months because of the 99 days. This was then the date that you passed to your XMLGregorianCalendar, which explains the output you got.
Links
XML Schema Part 2: Datatypes Second Edition, appendix D ISO 8601 Date and Time Formats
Wikipedia article: ISO 8601
Oracle tutorial: Date Time explaining how to use java.time.
Related
I have a problem on the java conversion of the dates.
I have input a String, YYYYMMDD, that converts to long and by executing the code the output is wrong
try {
//Current date to dd-mm-yyyy
Date currentDate = new Date(20161205); //or
DateFormat df = new SimpleDateFormat("dd-mm-yyyy");
String strCurrentDate = df.format(currentDate);
System.out.println("Date is " + strCurrentDate);
} catch (Exception e) {
System.out.println("Exception :" + e);
}
The output is: 01-49-1970
why?? How can I solve the problem
Solution:
Date currentDate = new Date(116,11,05);
Explanation:
You put single number as an argument of constructor of Date. If you take a look at list of available constructors of this class in Java API documentation here, you'll notice that the one taking long as argument will be chosen. As documentation states:
Date(long date) - Allocates a Date object and initializes it to represent the specified number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.
Instead of that, if you really need to use java.util.date package (java.time is considered as the right choice nowadays), consider using another constructor: Date(int year, int month, int date). In that case, you should pass the following numbers as parameters:
Date currentDate = new Date(116,11,05);
This is because:
year - the year minus 1900.
month - the month between 0-11.
date - the day of the month between 1-31.
By the way, consider using java.time package instead of java.util as java.util.Date is now deprecated.
you are doing it in the wrong way see
if you want to change date from this formate yyyyMMdd to this formateyyyy-MM-dd
you have to to change your code a little bit
try {
//Current date to dd-mm-yyyy
DateFormat fromFormate = new SimpleDateFormat("yyyyMMdd");
DateFormat toFormate = new SimpleDateFormat("yyyy-MM-dd");
String dateToFormate = "20161205"; //or
Date d=fromFormate.parse(dateToFormate);
System.out.println("Date is " + toFormat.formate(d));
} catch (Exception e) {
System.out.println("Exception :" + e);
}
tl;dr
LocalDate.parse(
"20161205",
DateTimeFormatter.BASIC_ISO_DATE
).format(
DateTimeFormatter.ofPattern("dd-MM-uuuu")
)
05-12-2016
Why 01-49-1970?
I cannot reproduce your exact output so can explain most of it, not all. Probably you’ve confused a couple of your test examples and didn’t get 01-49-1970 from new Date(20161205). On my computer I got Date is 01-36-1970. It’s bad enough.
As others have pointed out, new Date(20161205) gives you a point in time a little more than 20 000 seconds after the epoch of January 1, 1970 00:00 UTC. In UTC the time is then 5:36:01.205 (AM) on January 1. The time in your time zone probably differs. There are time zones where the date is still December 31, 1969.
But this doesn’t seem to explain how you seem to get an output in the 49th month of 1970, or I in the 36th month. This is because you used lowercase mm in your format pattern string. mm is for minute of hour. Uppercase MM is for month. So the 36 I got matches the minutes in the 5:36:01. There are time zones where the minutes are not the same; but I couldn’t find a time zone where the minute of hour is 49 at this time, so your exact reported output I cannot explain.
How can I solve the problem?
As others have said too, use java.time, the modern Java date and time API. It is so much nicer to work with.
LocalDate currentDate = LocalDate.of(2016, Month.DECEMBER, 5);
Or from a string:
LocalDate currentDate
= LocalDate.parse("20161205", DateTimeFormatter.BASIC_ISO_DATE);
Format to your desired output:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd-MM-uuuu");
String strCurrentDate = currentDate.format(dtf);
System.out.println("Date is " + strCurrentDate);
This prints
Date is 05-12-2016
As a bonus java.time will let you know through an exception if you happen to use mm instead of MM in the format pattern string above.
Link: Oracle Tutorial: Date Time explaining how to use java.time.
Like #oceano22 said, there are newer/better date/time packages available. That said, the reason this is happening is because when you called new Date(20161205) the parameter that date constructor takes is NOT yyyyMMdd. According to the javadoc... "Allocates a Date object and initializes it to represent the specified number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT."
So really you've created a date just 20 million milliseconds after the Unix epoch (Jan 1, 1970).
I've you're trying to get Dec 5, 2016 into a Date use df.parse("05-12-2016") with the SimpleDateFormat df you have defined.
You also likely want capital M's for month in your date format e.g. "dd-MM-yyyy" because lowercase m's are for minutes.
I am trying to convert ISO 8601 date string to epoch time. How do I handle negative dates? Is the below code correct? Should I use something else instead of simple date format library? Negative dates are for BC.
String formatString = "yyyy-MM-dd'T'hh:mm:ssX";
SimpleDateFormat formatter = new SimpleDateFormat(formatString);
Date date = formatter.parse("-2017-01-04T12:30:00+05:00");
System.out.println(date.getTime()/1000);
Answer: -125818806600L
TL;DR: No, your code is not correct. Yes, I recommend using the modern Java date and time API instead of SimpleDateFormat.
Your first issue is defining correctness for years before the common era (BCE, “before Christ”).
As I read Wikipedia, ISO 8601 does not define clearly how to interpret a date in that range. The year itself poses no great problem: “year 0000 being equal to 1 BCE”, so -1 is 2 BCE and -2017 is 2018 BCE. You may use the proleptic Gregorian calendar, produced by extending the Gregorian calendar backward to dates preceding its official introduction in 1582, but beware that this disagrees with the Julian calendar traditionally used, so when your date-time string says January 4th this is not the same day as January 4th in the history books. Also the use of negative years and the proplectic Gregorian calendar is not a requirement by ISO 8601, it is only by agreement between the parties. Reservation: I don’t know whether there is any definition of January 4, 2018 BCE in the history books; we’re way back before the introduction of the Julian calendar too (proposed by Julius Caesar in 46 BCE).
The documentation of SimpleDateFormat does not state how it handles dates before the introduction of the Gregorian calendar. It seems to depend on a Calendar object associated with the date/time formatter. Such a Calendar object would be a GregorianCalendar on most computers and JVMs, but not always. So I take it that the output from your code is not guaranteed to be the same on all computers. And a GregorianCalendar can and usually does handle dates from before pope Gregor in the Julian calendar, so I will expect that the result you got does agree with the history books, but not with ISO 8601, when it comes to establishing which day was January 4, 2018 BCE. So on these grounds I suspect that your result is not correct.
As a test I compared the output from your code with the output from a similar use of the Java date and time API. Running your code I too got -125818806600. So I tried:
System.out.println(OffsetDateTime.parse("-2017-01-04T12:30:00+05:00")
.toInstant()
.getEpochSecond());
These classes should be ISO 8601 compliant, so I would prefer this code over yours (it’s also a bit simpler). I got
-125817294600
It’s not the same, so another sign that your code does not give the correct result. The difference is 1512000 seconds, the same as 17 days 12 hours. Let me start by admitting I don’t understand. I would readily think that the difference between Julian and Gregorian calendar could account for a difference in the range of 17 or 18 days. But the 12 hours confuse me.
Edit: The 12 hours come from your use of lowercase hh in your format pattern string. Since you don’t have an AM/PM marker, you should use uppercase HH. Correcting this error, the output from your code is
-125818763400
Now the difference between your code and mine is 1468800 seconds or precisely 17 days.
hh is for hours within AM or PM in the range 1–12. Uppercase HH is for hour in day, 0–23. It’s a very common mistake with SimpleDateFormat (not with the modern classes, they catch it so you correct it). It goes unnoticed scaringly often because for most hours the result is the same; SimpleDateFormat is happy to use AM as default and parse for example 14:30 and understand it as 2:30 PM. But since the hours in your string happen to be 12, there is a difference: 12:30 AM means 0:30 in the day, where in ISO 12:30 means 12:30 PM. Hence the 12 hours error.
I m writing a program which involves converting java.util.Date to java.sql.Date...
I've done it using getTime() method...
java.util.Date dt = new java.util.Date();
java.text.DateFormat df = new java.text.SimpleDateFormat("dd/MM/yyyy");
dt=df.parse("06/12/0785");
java.sql.Date sqldate = new java.sql.Date(dt.getTime());
System.out.print("\n\n\n "+dt.getTime()+" "+sqldate);
I m getting a negative value for dt.getTime() and the value is correct for sqldate...
The doubt i've is
`Is it safe to use negative seconds as epoch or is it vulnerable to bugs while implementing it in database in any way.....???
AND
It's printing wrong date for sqldate on setting date as 00/00/0000 instead of the one mentioned in the example....what might be the cause......and does there lie a solution.......???
If you parse a "00" as month, it will be regarded as December. The day "00" is the last day of the previous month, so the combinations is parsed as the 30th of November. As for the zero year, see Year 0000 in java. Negative values for .getTime() are no problem at all.
Well, in epoch time, "0" would be the equivalent to January 1, 1970. Any date earlier than that would come out negative when you try to parse it.
Try changing the date string you are parsing to any date after 1970 and you will get a proper value.
Documentation says negative values are valid for java.sql.Date's constructor and setTime method:
http://docs.oracle.com/javase/6/docs/api/java/sql/Date.html#setTime(long)
I expect that using "00/00/0000" as a date is a problem as there is no zero month, day, or year.
http://en.wikipedia.org/wiki/0_(year)
The legacy date-time API (java.util date-time types and their formatting type, SimpleDateFormat etc.) is outdated and error-prone. Let's first understand how SimpleDateFormat erroneously processes a string like 00/00/0000 and later we will cover how the modern date-time API prevents an attempt to processes an invalid string like this.
The following demo will help us understand easily both, the concept and the problem:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdfInput = new SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH);
SimpleDateFormat sdfOutput = new SimpleDateFormat("dd MMMM yG", Locale.ENGLISH);
System.out.println(sdfOutput.format(sdfInput.parse("00/00/2021")));
}
}
Output:
30 November 2020AD
Some facts about SimpleDateFormat:
SimpleDateFormat processes the month, 1 as January.
It processes the year, month and day-of-month in a circular fashion which is very similar to how int, and long are processed.
For the sake of completeness, look at the output of the following statements:
System.out.println(Integer.MAX_VALUE + 1); // -2147483648
System.out.println(Integer.MIN_VALUE - 1); // 2147483647
Based on this concept, this is how SimpleDateFormat has parsed 00/00/2021:
Month, 00: Go back to the last month i.e. December which also means the year will become 2020.
Day-of-month, 00: Go back to the last day of the last month which also means December will shift back one place to become November and the last day of November is 30.
Thus, the output will be 30 November 2020AD.
Quiz: What will be the output for the input string, -01/-01/2021?
If your answer is: 30 October 2020AD, you have understood it correctly.
Given below are some more examples:
SimpleDateFormat sdfInput = new SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH);
SimpleDateFormat sdfOutput = new SimpleDateFormat("dd MMMM yG", Locale.ENGLISH);
System.out.println(sdfOutput.format(sdfInput.parse("00/00/0000"))); // 30 November 2BC
System.out.println(sdfOutput.format(sdfInput.parse("00/-01/2021"))); // 31 October 2020AD
System.out.println(sdfOutput.format(sdfInput.parse("00/13/2021"))); // 31 December 2021AD
System.out.println(sdfOutput.format(sdfInput.parse("00/14/2021"))); // 31 January 2022AD
Why 2BC?
Luckily1. there is no year-0. Before 1AD, we have 1BC. So, we know year-0 as 1BC. If you go one year back, it will be 2BC. You would like to check this answer for some more explanation.
You will encounter many such surprises while using the legacy date-time API. For these reasons, it is recommended to stop using it completely and switch to java.time, the modern date-time API*.
java.time
Let's see how java.time, the modern API prevents an attempt to processes an invalid string like this:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
LocalDate.parse("00/00/0000", DateTimeFormatter.ofPattern("dd/MM/uuuu", Locale.ENGLISH));
}
}
Output:
Exception in thread "main" java.time.format.DateTimeParseException:
Text '00/00/0000' could not be parsed: Invalid value for MonthOfYear
(valid values 1 - 12): 0
Learn more about java.time, the modern date-time API2. from Trail: Date Time.
1. Otherwise, it would have opened a can of worms regarding whether year-0 should be called 0AD or 0BC.
2. For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
The code
String strDate = "2010-12-01";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd");
Date parsedDate = sdf.parse(strDate);
System.out.println(parsedDate);
will, dependend on your locale, produce the following output:
Fri Jan 01 00:12:00 CET 2010
The date is not parsed correctly, since i expect the 1st dec and not the 1st jan.
I know, months are numbered from 0 to 11, so the 12 becomes a 0 for january.
I have several solutions for this problem in mind, but all of them will produce at least 3-4 additional lines of code. So my question is:
What is the nicest way to solve this "problem"?
I can't imagine that it takes more than 2-3 lines to parse a simple date...
//edit: Shame on me for this question. Forgive me. thx folks
change yyyy-mm-dd to yyyy-MM-dd
M Month in year Month July; Jul; 07
m Minute in hour Number 30
See
SimpleDateFormat
Your date format is incorrect: Months are MM (not mm, which is for minutes). Try this:
"yyyy-MM-dd"
The reason you are getting January is that you haven't given a month to the parser (you gave year-minute-day). January, the first month, is the default month allocated to the date if not provided by the input. The 12 got parsed into the minute field (fairly obviously)
What is the nicest way to solve this "problem"?
Use different classes. You are using troublesome old legacy classes. Instead use the java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone. It counts months sensibly, 1-12 is January through December.
Your input string is already in one of the ISO 8601 formats. These standard formats are used by default in the java.time classes. So no need with defining a formatting pattern.
LocalDate localDate = LocalDate.parse( "2010-12-01" );
Month
Also check out the handy Month enum.
Month month = Month.of( 1 ); // January = 1, December = 12.
I am using SimpleDateFormat to display a Calendar like this :
public String getDate()
{
String DATE_FORMAT = "EEEE, dd/MM/yyyy HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
System.err.println(date.getTime().getMonth());
return sdf.format(date.getTime());
}
The shell returns 6 and the display : mardi, 06/07/2010 12:44:52
It can't be possible ? Why ?
Thanks
From the Java API:
public int getMonth()
Returns a number representing the month that contains or begins with the instant in time represented by this Date object. The value returned is between 0 and 11, with the value 0 representing January.
Unfortunately, months in class Date and class Calendar are zero-based. (In my opinion, this was a huge design mistake in those classes, and it's just one of the many design mistakes in Java's date and time API).
Note that class Calendar has constants to represent the months: Calendar.JANUARY, Calendar.FEBRUARY etc. Use those instead of the raw numbers.
An often mentioned, much better date and time API for Java is Joda Time. Note that there is a proposal to add a new date and time API to the next version of Java that will be based on Joda Time.
the getMonth method in Date is 0 indexed. from the JavaDoc:
Returns a number representing the month that contains or begins with the instant in time represented by this Date object. The value returned is between 0 and 11, with the value 0 representing January.
month index starts from 0 just like array index
that's your locale set to france DD/MM/YY so it is tuesday, July, 2010.
the 6th month is july if it starts at 0.