using java epoch seconds in negative - java

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.

Related

How to print date 9999-99-99 in xmlgregoriancalendar?

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.

Not able to get difference between two datetime?

Please check the below code. I am trying to get the difference but every time getting 0.
Can anybody please point me what is the problem with below code?
SimpleDateFormat sDateFormat = new SimpleDateFormat("hh:mm:ss dd/mm/yyyy");
try {
long d1 = sDateFormat.parse("10:04:00 04/04/2014").getTime();
long d2 = sDateFormat.parse("10:09:00 04/04/2014").getTime();
long difference = d2 - d1;
Log.i(TAG,">> Difference = "+difference);
} catch (ParseException e) {
e.printStackTrace();
}
your formatter does not fit the date format used.
Try:
new SimpleDateFormat("HH:mm:ss dd/MM/yyyy");
From Android Developer documentation of SimpleDateFormat, you can see M is for Month and m is for minute...
M month in year (Text) M:1 MM:01 MMM:Jan MMMM:January MMMMM:J
m minute in hour (Number) 30
So, you should change the date format from this...
hh:mm:ss dd/mm/yyyy
to this...
hh:mm:ss dd/MM/yyyy
I hope this format correction will solve your problem.
Your format, hh:mm:ss dd/mm/yyyy has two problems:
h is used for 12-Hour time format i.e. a time format with AM/PM marker which is not the case with your date-time strings. You need to use H which is used for a 24-Hour time format.
m is not used for a month. For a month, you need to use M.
Apart from this, 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, the modern date-time API*.
Demo using modern date-time API:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String args[]) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("H:m:s d/M/u");
LocalDateTime start = LocalDateTime.parse("10:04:00 04/04/2014", dtf);
LocalDateTime end = LocalDateTime.parse("10:09:00 04/04/2014", dtf);
long diff = ChronoUnit.MILLIS.between(start, end);
System.out.println(diff);
}
}
Output:
300000
Learn more about the 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.

Convert "Friday, February 1, 2013" to "2013-02-01"

How can I perform this conversion in Java?
Currently, I'm doing:
public static String formatDate(String strDateToFormat) {
try {
SimpleDateFormat sdfSource = new SimpleDateFormat("EEEE, MMMM DD, YYYY");
Date date = sdfSource.parse(strDateToFormat);
SimpleDateFormat sdfDestination = new SimpleDateFormat("yyyy-MM-dd");
return sdfDestination.format(date);
} catch (ParseException pe) {
System.err.println("Parse Exception : " + pe);
}
return null;
}
However, this results in an incorrect format. It gives me the following output:
Friday, February 1, 2013 > 2013-01-04
Thursday, January 31, 2013 > 2013-01-03
You're using DD in your parsing part, which is the day of year. You want dd instead. You also probably want yyyy (year) instead of YYYY (week year). (In most cases they're the same value, but not always.)
You're using DD in your parsing part, which is the day of year. You want dd instead.
Change also YYYY in yyyy.
You can find all patterns here.
http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
Your code has got two major problems and the existing answers have already solved one of them. The second and even more dangerous problem is, not using Locale with SimpleDateFormat, which is a Locale-sensitive type. Since your Date-Time string is in English, make sure to use Locale.ENGLISH or some other English-Locale. So, a correct initialization would be:
SimpleDateFormat sdfSource = new SimpleDateFormat("EEEE, MMMM d, y", Locale.ENGLISH);
Check Never use SimpleDateFormat or DateTimeFormatter without a Locale to learn more about it. Also, notice a single d which, for parsing, can cater to both single-digit as well as double-digit representation of a day-of-month. Similarly, a single y can cater to both two-digit as well as four-digit representation of a year.
Switch to 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 with Java SE 8 in March 2014.
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) {
String input = "Friday, February 1, 2013";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEEE, MMMM d, u", Locale.ENGLISH);
LocalDate date = LocalDate.parse(input, dtf);
System.out.println(date);
}
}
Output:
2013-02-01
ONLINE DEMO
Some notes:
Here, you can use y instead of u but I prefer u to y.
The LocalDate#toString gives you a String in [ISO-8601 format] which is the exact same format you are expecting. So, you do not need to format LocalDate explicitly to obtain a String in this format.
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.

Why don't I get the year right using SimpleDateFormat in java?

I trying to parse a data in a MySql Format, I ran across SimpleDateFormat. I can get the proper day and month, but I got a strange result for the year :
date = 2009-06-22;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(date);
System.println(date);
System.println(d.getDate());
System.println(d.getMonth());
System.println(d.getYear());
Outputs :
2009-06-22
22 OK
5 Hum... Ok, months go from 0 to 11
109 o_O WTF ?
I tried changing the format to YYYY-MM-dd (got an error) and yy-MM-dd (did nothing). I am programming on Android, don't know if it's important.
For now, I bypass that using a split, but it's dirty and prevent me from using i18n features.
The year is relative to 1900. That's a "feature" of the Date class. Try to use Calender.
Thanks to Aaron, the right version :
Calendar c = Calendar.getInstance();
c.setTime(sdf.parse(date));
System.println(c.get(Calendar.YEAR));
java.time
The existing answers have already explained correctly how java.util.Date returns the year relative to 1900 and how you can get around the problem by using java.util.Calendar.
The question and existing answers use java.util date-time API and SimpleDateFormat which was the correct thing to do in 2009. In Mar 2014, the java.util date-time API and their formatting API, SimpleDateFormat were supplanted by the modern date-time API. Since then, it is highly recommended to stop using the legacy date-time API.
Using java.time, the modern date-time API:
You do not need a DateTimeFormatter: java.time API is based on ISO 8601 and therefore you do not need a DateTimeFormatter to parse a date-time string which is already in ISO 8601 format e.g. your date string, 2009-06-22 which can be parsed directly into a LocalDate instance which contains just date units.
Demo:
import java.time.LocalDate;
class Main {
public static void main(String args[]) {
String strDateTime = "2009-06-22";
LocalDate date = LocalDate.parse(strDateTime);
System.out.println(date);
System.out.printf("Day: %d, Month: %d, Year: %d", date.getDayOfMonth(), date.getMonthValue(), date.getYear());
}
}
Output:
2009-06-22
Day: 22, Month: 6, Year: 2009
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.

Getting today's date in java - I've tried the regular ways

I need today's date - and zero anything else (" 05/06/08 00:00:00 ")
I've tried
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR, 0);
Date date1 = calendar.getTime();
System.out.println(date1);
Run: (This is seriously messed up)
If the hour on the computer is < 12:00 at noon : Sun Mar 08 00:44:39 IST 2009
If the hour on the computer is > 12:00 at noon : Sun Mar 08 12:46:53 IST 2009
So I gave this up.
All the Date's setters are deprecated (except the epoch time) - so I don't want to use them either
The only thing I could think of is
Calendar calendar = Calendar.getInstance();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
String sDate = dateFormat.format(calendar.getTime());
Date today = dateFormat.parse(sDate);
But this is such a lame code I can't bring myself to write it.
Any other option?
Thanks!
I use this:
public static Date startOfDay(Date date) {
Calendar dCal = Calendar.getInstance();
dCal.setTime(date);
dCal.set(Calendar.HOUR_OF_DAY, 0);
dCal.set(Calendar.MINUTE, 0);
dCal.set(Calendar.SECOND, 0);
dCal.set(Calendar.MILLISECOND, 0);
return dCal.getTime();
}
My standard advice for Java date/time questions: don't use java.util.{Calendar,Date}. Use Joda Time. That way you can represent a date as a date (with no associated time zone), instead of a date/time. Or you could use a DateMidnight if that's what you want to represent. (Be careful of combinations of time zone and date where there is no midnight though...)
What do you need to use the Date with? If you can get away with changing to use Joda throughout, that's great. Otherwise, you can use Joda to do what you want and then convert to milliseconds (and then to java.util.Date) when you really need to.
(Michael's solution when using Date/Calendar is fine if you really want to stick within a broken API... but I can't overstate how much better Joda is...)
You should use HOUR_OF_DAY instead of HOUR and combine it with MINUTE and SECOND also.
import java.util.Calendar;
import static java.util.Calendar.HOUR_OF_DAY;
import static java.util.Calendar.MINUTE;
import static java.util.Calendar.SECOND;
import static java.util.Calendar.MILLISECOND;
public class Today {
public static void main( String [] args ) {
Calendar cal = Calendar.getInstance();
cal.set( HOUR_OF_DAY, 0 );
cal.set( MINUTE, 0 );
cal.set( SECOND, 0 );
cal.set( MILLISECOND, 0 );
System.out.println( cal.getTime() );
}
}
The results you are getting are due to HOUR is used to AM/PM while HOUR_OF_DAY is 24 hrs.
HOUR_OF_DAY:
Field number for get and set indicating the hour of the day. HOUR_OF_DAY is used for the 24-hour clock. E.g., at 10:04:15.250 PM the HOUR_OF_DAY is 22.
HOUR:
Field number for get and set indicating the hour of the morning or afternoon. HOUR is used for the 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12. E.g., at 10:04:15.250 PM the HOUR is 10.
The time component is not just hours (and Calendar.HOUR is, as you have noticed, AM/PM).
You need to set all of the time fields to 0: HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND.
See Apache's commons-lang DateUtils.truncate()
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 has many types which truly represent a date or time or date-time in a specific timezone. You can choose from the following options as per your specific requirement:
If you are looking for a type that represents a date without a timezone, you can use LocalDate.now. The good news is that its variant, LocalDate#now(ZoneId) returns the current date from the system clock in the specified time-zone.
If you are looking for an object that represents a date without a timezone, and with time units set to zero, you can call LocalDate#atStartOfDay on the object obtained with Option#1.
If you are looking for an Instant representing the Date-Time object obtained with Option#2, you can attach this object with ZoneId.of("Etc/UTC") using LocalDateTime#atZone to obtain a ZonedDateTime and convert the same into an Instant using ZonedDateTime#toInstant.
Demo:
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
LocalDate todayInSystemTz = LocalDate.now();
System.out.println(todayInSystemTz);
LocalDate todayInIndia = LocalDate.now(ZoneId.of("Asia/Kolkata"));
System.out.println(todayInIndia);
LocalDateTime todayInSystemTzWithZeroTimeUnits = todayInSystemTz.atStartOfDay();
System.out.println(todayInSystemTzWithZeroTimeUnits);
ZonedDateTime todayInUtcWithZeroTimeUnits = todayInSystemTzWithZeroTimeUnits.atZone(ZoneId.of("Etc/UTC"));
System.out.println(todayInUtcWithZeroTimeUnits);
Instant instant = todayInUtcWithZeroTimeUnits.toInstant();
System.out.println(instant);
// Can I represent the obtained Instant in India?
System.out.println(instant.atZone(ZoneId.of("Asia/Kolkata")));
// Can I represent the obtained Instant in New York?
System.out.println(instant.atZone(ZoneId.of("America/New_York")));
}
}
Output:
2021-06-20
2021-06-20
2021-06-20T00:00
2021-06-20T00:00Z[Etc/UTC]
2021-06-20T00:00:00Z
2021-06-20T05:30+05:30[Asia/Kolkata]
2021-06-19T20:00-04:00[America/New_York]
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).
For any reason, if you need to convert this object of Instant to an object of java.util.Date**, you can do so as follows:
Date date = Date.from(instant);
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.
**
A java.util.Date object simply represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). 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);
As mentioned above you should use
Calendar.HOUR_OF_DAY
As opposed to
Calendar.HOUR
Also you need to clear out the other fields (Calendar.MINUTE, Calendar.SECOND, and Calendar.MILLISECOND) by setting them to zero.
Sorry there's no easy way here. A pain, and that's why they're working on a new API for Java 7 I believe based on Joda Time.
...or you can do it the hacker way:
long MS_PER_DAY = 86400000L;
Date dateTime=new Date();
long offset = TimeZone.getDefault().getOffset(dateTime.getTime());
Date date= new Date(((dateTime.getTime()+offset)/MS_PER_DAY)*MS_PER_DAY-offset);
I know this is a very old question, no longer active, but it came to be on the top when I searched Google.
While all advise is very good, I can't believe no one simply answered:
Date date = new Date(System.currentTimeMillis());
System.out.println(date);
Which returns effectively, today's date.
Why the string manipulation?
Can you not just set the values you need on the Calendar object before converting to a Date using getTime()?
Another vote for JodaTime.
java.util.Date and Calendar are so bad they are broken. (And SimpleDateFormat is rubbish too!)
For what it's worth, Java 7 will include a new date time library based strongly around JodaTime.

Categories