What time is the start of a day, say 01/01/2010?
Is it 00:00:00:000 ? or is that midnight?
[edit]
It might be a stupid question but I'm confused because I used Calendar.set(Calendar.HOUR, 0) but this gives me a time of 12:00:00.
and now I've realised I should be using HOUR_OF_DAY
The start of the day isn't always midnight. It can depend on the time zone and date. (If the clock moves forward an hour at the start of the day, it will start at 1am.)
That's why Joda-Time has things like LocalDate.toDateTimeAtStartOfDay - and they're well worth using.
But yes, normally it's at 00:00:00 which is midnight. (This can also be formatted as "12am" depending on your locale etc.)
java.time
Normally, the start of the date is 00:00 hours but it may vary because of DST. Therefore, instead of assuming it to be 00:00 hours, the safest option is to use LocalDate#atStartOfDay(ZoneId zone).
Demo:
import java.time.LocalDate;
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) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M/d/u", Locale.ENGLISH);
LocalDate date = LocalDate.parse("01/01/2010", dtf);
// In JVM's timezone
ZonedDateTime startOfDay = date.atStartOfDay(ZoneId.systemDefault());
System.out.println(startOfDay);
// In custom timezone
startOfDay = date.atStartOfDay(ZoneId.of("Africa/Johannesburg"));
System.out.println(startOfDay);
}
}
Output:
2010-01-01T00:00Z[Europe/London]
2010-01-01T00:00+02:00[Africa/Johannesburg]
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.
ZonedDateTime from java.time
Like Arvind Kumar Avinash already does in a good answer, I recommend that you use java.time, the modern Java date and time API, for your date and time work.
If you had got a LocalDate or a string holding a date without time of day, that answer shows you how to get the start of the day (the first moment of the day). If you had already got a ZonedDateTime, you may simply use its truncatedTo method. Let’s take one of those interesting examples where the clocks are turned forward at 00:00 so the first moment of the day is 01:00:
ZonedDateTime zdt = ZonedDateTime.of(
2000, 9, 17, 15, 45, 56, 789000000, ZoneId.of("Asia/Dili"));
System.out.println("We got date and time: " + zdt);
ZonedDateTime startOfDay = zdt.truncatedTo(ChronoUnit.DAYS);
System.out.println("Start of day is: " + startOfDay);
Output:
We got date and time: 2000-09-17T15:45:56.789+09:00[Asia/Dili]
Start of day is: 2000-09-17T01:00+09:00[Asia/Dili]
What went wrong in your code?
You’ve already said it in an edit to the question, but it deserves to be mentioned in an answer too: Calendar.HOUR refers to, from the documentation:
Field number for get and set indicating the hour of the morning or
afternoon. HOUR is used for the 12-hour clock (0 - 11). …
So if your Calendar was already holding a time in the afternoon (12 noon or later), setting HOUR to 0 gives you 12 noon (12:00 on a 24 hour clock), not 12 midnight (00:00 on a 24 hour clock). Except that the time of the hour may still be non-zero, so you may also get, for example, 12:34:45.567. The Calendar class was cumbersome to work with.
In any case the Calendar class was poorly designed and is long outdated, so you shouldn’t need to worry; just don’t use that class anymore.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Documentation of Calendar.HOUR.
Related
I was trying to get milliseconds from epoch until 2020.01.01. I used old method with Date and I also wanted to use new sexy LocalDate but two results I got are different:
long millisecondsInTheDay = 24 * 60 * 60 * 1000;
long millis1 = LocalDate.of(2020, Month.JANUARY, 1).toEpochDay() * millisecondsInTheDay; // 1577836800000
long millis2 = new Date(2020 - 1900, 0, 1).toInstant().toEpochMilli(); // 1577833200000
Difference is exactly one hour (3600_000 milliseconds). Why I get different result?
I don't want to comment on why you get a difference because I think that both of the original approaches are problematic. You need to pay close attention to things like time zones; and you really should avoid doing any sort of arithmetic on numerical values representing dates.
You need to pay special care to specify the points you are measuring between: if you want a number of milliseconds, presumably you really want to specify those points as instants in time. "1970" isn't an instant, it's a year-long period; "2020-01-01" isn't an instant either, but a period whose meaning shifts depending on time zone - there's roughly 48h-worth of instants where somewhere on the planet it is considered to be that date.
The correct way to do this (assuming you want milliseconds between epoch and the start of the day in your preferred timezone) is:
Duration between =
Duration.between(
Instant.EPOCH,
LocalDate.of(2020, Month.JANUARY, 1).atStartOfDay(zoneId));
long betweenMillis = between.toMillis(); // If you must - better to keep the type information that this is a Duration.
Note that you need to specify the zoneId, e.g. ZoneId.of("Europe/Warsaw"), because that affects when the start of the day is, and hence how many milliseconds.
Different time zones
Why I get different result?
Joachim Sauer said it already: This is because of different time zones. millis1 is the count of milliseconds until January 1, 2020 at 00:00 in UTC. millis2 counts until January 1, 2020 at 00:00 in your local time zone, presumably Europe/Warsaw. In winter Poland is at offset +01:00 from UTC, which explains the difference of 1 hour between the two. Everything agrees nicely. The epoch is one point in time and independent of time zone. It’s usually defined as January 1, 1970 at 00:00 in UTC.
That said I agree with Andy Turner that both ways to calculate are problematic.
A good calculation with java.time
Here’s my go, of course using java.time, the modern Java date and time API:
ZoneId targetZone = ZoneOffset.UTC;
long millis = LocalDate.of(2020, Month.JANUARY, 1).atStartOfDay(targetZone)
.toInstant()
.toEpochMilli();
System.out.println(millis);
Output:
1577836800000
If you did want your own time zone, just change the first line:
ZoneId targetZone = ZoneId.of("Europe/Warsaw");
1577833200000
The key is to use the same timezone (e.g. UTC) for both, the legacy and the modern API.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneOffset;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
long millisUsingJavaUtilDate = sdf.parse("2020.01.01")
.getTime();
long millisUsingJavaTime = LocalDate.of(2020, Month.JANUARY, 1)
.atStartOfDay(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
System.out.println(millisUsingJavaUtilDate);
System.out.println(millisUsingJavaTime);
}
}
Output:
1577836800000
1577836800000
Let's try with another timezone, America/New_York:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
long millisUsingJavaUtilDate = sdf.parse("2020.01.01")
.getTime();
long millisUsingJavaTime = LocalDate.of(2020, Month.JANUARY, 1)
.atStartOfDay(ZoneId.of("America/New_York"))
.toInstant()
.toEpochMilli();
System.out.println(millisUsingJavaUtilDate);
System.out.println(millisUsingJavaTime);
}
}
Output:
1577854800000
1577854800000
Learn more about 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, the modern date-time API* .
* 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.
new Date( y , m , d ) uses default time zone
Some of the other Answers are correct and very useful. But I want to make very plain and simple where your code went wrong:
➥ The deprecated constructor of java.util.Date for year-month-day arguments implicitly applies your JVM’s current default time zone.
Take the first part of the key line in your code:
new Date(2020 - 1900, 0, 1).toInstant()
… where an Instant is always in UTC (an offset of zero hours-minutes-seconds), by definition. On my machine the current default time zone in my JVM is America/Los_Angeles. On your date and time, this zone was eight hours behind UTC.
So let's try these three lines of code code:
System.out.println(
ZoneId.systemDefault()
);
System.out.println(
new Date(2020 - 1900, 0, 1)
);
System.out.println(
new Date(2020 - 1900, 0, 1).toInstant()
);
When run, we see indeed that the moment represented by new Date is the first moment of that day as seen in the time zone America/Los_Angeles, colloquially known as PST. That zone on that date is eight hours behind UTC. We can see this fact in the third line, when calling toInstant has adjusted to UTC where the time-of-day is 8 AM.
America/Los_Angeles
Wed Jan 01 00:00:00 PST 2020
2020-01-01T08:00:00Z
Avoid Date
In the bigger picture, stop using Date class!
There are no benefits to be had by studying the behavior of java.util.Date. That class is absolutely terrible, written by people who did not understand date-time handling. Along with Calendar, java.sql.Date, and SimpleDateFormat, these classes should never be used.
These legacy classes were supplanted years ago by the java.time classes, defined in JSR 310. Sun, Oracle, and the JCP community unanimously gave up on these classes. So should you.
Your problem is here:
long millis1 = LocalDate.of(2020, Month.JANUARY, 1).toEpochDay() * millisecondsInTheDay; // 1577836800000
You use the LocalDate class, which gets for you the local time (in your timezone) while time in Java (in millisec) is the amount of time elapsed between 01.01.1970 UTC (Universal Coordinated Time) this is (at the date you requested, 01.01.2020 00:00:00 UTC):
1577836800000
The difference you get is due to the time offset observed at your local time (one hour, probably you are in central european time --CET--)
Edit:
By the way, I've seen in the answers (and in your code) that you use:
new Date(2020 - 1900, 0, 1);
This is very bad code. You are assuming that the above is equivalent to the difference in milliseconds that will be between the dates 2020.1.1 and 1900.1.1 and indeed, it represents the timestamp at date 120.1.1 this is the timestamp at the first of january of year one hundred and twenty (a.C) There's no distributive property between dates in new Date() operator. And if the years were all the same duration, this could be true... but they are not. A good way would be to use:
long millis = new Date(2020, 0, 1).getTime() - new Date(1900, 0, 1).getTime();
but the later is not equivalent to what is written above.
Could some one explain why this past date getting increased by one hour , when I convert it to Moscow Timezone ?
I'm using JDK 1.6.0_12 version. .
2011-04-02T11:39:46+0300 --> Sat Apr 02 12:39:46 MSK 2011 // 11:39 --> 12:39
My current system time-zone is "Europe/Moscow" UTC+3 .
Also please note that this past date is in DST(Daylight Saving ) time-zone period UTC+4 , earlier used in Russia.
There was a legislative change of Russian time-zone definitions in October 2014 . Since then Russia uses UTC+3 all through out a year .
I already checked
this old post of 2014 . But I think this issue looks different.
Our developers expect that every past date (like "2011-04-02T11:39:46+0300" and which is in DST period ), should contain current time zone offset value i.e +0300 , not +0400 . And they think JRE is converting it incorrectly to UTC+4 , though "Default Time Zone Offset" shows +3 here . Is this way of handling time-zone offset value for past dates correct?
Same output is given on JRE 1.8 , which I think is an updated version ,there shouldn't be any issue in TZ definition in JRE 1.8.
Thanks in Advance !
Java Code:
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Date;
public class HelloWorld{
public static void main(String []args)
{
String dateInString = "2011-04-02T11:39:46+0300";
System.out.println(dateInString);
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date date = dateFormat.parse(dateInString);
System.out.println(date);
} catch (Exception e) {
System.out.println(e);
}
final TimeZone tzone = TimeZone.getDefault();
System.out.println("Default Time Zone ID - " + tzone.getID());
System.out.println("Default Time Zone Offset - (" + (tzone.getRawOffset() / 60 / 60 / 1000) + ") hour.");
}
}
Output :
2011-04-02T11:39:46+0300
Sat Apr 02 12:39:46 MSK 2011
Default Time Zone ID - Europe/Moscow
Default Time Zone Offset - (3) hour.
12:39 is the correct time
You are getting the correct result. In your string, 2011-04-02T11:39:46+0300, the trailing +0300 is an offset from UTC. So the point in time is the same as 2011-04-02T08:39:46+00:00 (UTC). As you say yourself, Moscow was at UTC offset +04:00 from 27 March 2011 to 26 October 2014. So to get the correct time for Moscow Java needs to add 1 hour to the hour in the string. Or 4 hours to the UTC hour of 08:39:46. In any case the time in Moscow was 12:39:46 at this point in time.
Or to answer your question:
… why this past date getting increased by one hour , when I convert it
to Moscow Timezone ?
Because Moscow on that date was 1 hour ahead of the time in the string.
java.time
That said I agree with those who recommend java.time, the modern Java date and time API, for the job. SimpleDateFormat is a notorious troublemaker of a class, and Date and TimeZone are poorly and confusingly designed too. All are long outdated. The modern API is so much nicer to work with.
For example:
ZoneId zone = ZoneId.of("Europe/Moscow");
ZonedDateTime zdt = ZonedDateTime.of(2011, 4, 2, 11, 39, 46, 0, zone);
System.out.println(zdt);
Output:
2011-04-02T11:39:46+04:00[Europe/Moscow]
You can also see from the output that Java knows that Moscow was at offset +04:00 back then.
Your question very well illustrates why java.time (opposite the old TimeZone class) makes the distinction between a time zone and an offset. A time zone includes all historic, the present and all known future offsets from UTC. This is what you need to represent historic times in Moscow correctly. In java.time a time zone is identified by a ZoneId object and obeys a ZoneRules object (most often we need not concern ourselves with the latter and can just trust Java to make the right conversions). A UTC offset is represented by a ZoneOffset object.
Question: how could I use java.time with Java 1.6?
This is your lucky day. java.time exactly requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Time Changes in Moscow Over the Years
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
Java 8+ APIs available through desugaring
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Both modern java date/time api and legacy one (that is used in jdk1.6) rely on system unix time and the tzdata file bundled with the JRE. Looks like the developers are right and your java is using a very old one version of tzdata and your developers are right.
Also, the tzdata keeps information about legal changes and if you are trying to convert date/time in the past, it will apply conversion rules that were relevant at that time.
Regarding JDK 1.8: there was an update to Russian timezone information in 8u101, so you should use at least 8u101 for a better timezone conversion.
The best decision for you would be to use modern java or update your JREs tzdata manually if you really need to use an old one.
You need to set time-zone to SimpleDateFormat as shown below:
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 dateInString = "2011-04-02T11:39:46+0300";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
dateFormat.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));// Set time-zone
Date date = dateFormat.parse(dateInString);
System.out.println(dateFormat.format(date));
}
}
Output:
2011-04-02T12:39:46+0400
Note that java.util.Date does not have time-zone information. It's simply the number of milliseconds from the standard Java epoch of 1970-01-01T00:00:00Z where Z stands for UTC (0 hour offset), also known as Zulu time-zone. At any given moment, you will get the same number of milliseconds on the JVMs sitting in any part of the word. When you try to print an object of java.util.Date, the date-time string for the JVM's time-zone is calculated from this milliseconds value and the same is displayed. If you want to get the date-time String in a specific time-zone, you need to set it explicitly to the SimpleDateFormat and use the same to format the java.util.Date.
This question already has answers here:
How to check if time in day is between two times?
(5 answers)
Closed 5 years ago.
How can I convert one specific hour, e.g. 18:00, to milliseconds?
I need this so that if it's between for example 12:00 and 18:00 I can do something, and if it is not between 12:00 and 18:00 I can do something else.
I get the current time with:
Private long time;
time = System.currentTimeMillis();
But I don't know how to convert an hour to milliseconds.
I searched on the Internet and it seems that if I use System.currentTimeMillis() it will give me the millisecond of the current day and hour but I need it to update for every day something like this:
Today the time in millis is something like this: 1516994140294. But this number contains this: Fri Jan 26 2018 19:15:40. So if I use the millis for 12:00 and 18:00 of this day this means that tomorrow it will not work as I want.
So can you help me with an example or documentation? Everything can help me :) and thanks in advance.
tl;dr
LocalTime.now() // Capture current moment. Better to explicitly pass a `ZoneId` object than rely implicitly on the JVM’s current default time zone.
.isBefore( LocalTime.of( 18 , 0 ) ) // Compare the current time-of-day against the limit.
No need for milliseconds count
No need to count milliseconds. Java has smart date-time classes for this work, found in the java.time package built into Java 8 and later. For earlier Android, see the last bullets below.
No need for System.currentTimeMillis(). The java.time classes do the same job.
LocalTime
To get the current time of day, without a date and without a time zone, use LocalTime.
Determining the current time requires a time zone. For any given moment, the time-of-day varies by zone. If omitted, the JVM’s current default time zone is applied implicitly. Better to explicitly specify your desired/expected time zone, as the default may change at any moment before or during runtime.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalTime now = LocalTime.now( z ) ;
Compare with methods isBefore, isAfter, and equals.
A shorter way of asking "is equal to or later than noon" is "is not before noon".
boolean isAfternoon =
( ! now.isBefore( LocalTime.NOON ) )
&&
now.isBefore( LocalTime.of( 18 , 0 ) )
;
If you are concerned about the effects of anomalies such as Daylight Saving Time( DST), explore the use of ZonedDateTime instead of mere LocalTime.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
Split the current time by the ':' delimiter. The first is hours, second is minutes, third is seconds.
Convert the hours to minutes. That is, 18*60.
Add the above answer to the current minutes (18*60 + 00) in this case.
Take the above answer and multiply by 60 for seconds ((18*60 + 00)*60).
Again, take the above, and add your seconds ((18*60 + 00)*60 + 00) in this case.
Again, take the above, multiply by 1000 for milliseconds (((18*60 + 00)*60 + 00)*1000).
Viola, you have your time in milliseconds.
You should take a look at
SimpleDateFormat
There's a good tutorial here
To compare two "dates" you should look at how to create a Calendar (or the more simplified but deprecated Date) object. It implements comparable, so you can convert the current time into a Date object and compare it to known timestamps (like in your question):
Jave Calendar
Java Date
You can set both Calendar and Date to a specific time or the current time. For example Calendar.setCurrentTimeMillis(System.currentTimeMillis()) will get a Calendar instance set the current time (just like Calendar.getInstance()).
Here's an example with Date:
// This is how to get today's date in Java
Date today = new Date();
//If you print Date, you will get un formatted output
System.out.println("Today is : " + today);
//formatting date in Java using SimpleDateFormat
SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy");
String date = DATE_FORMAT.format(today);
System.out.println("Today in dd-MM-yyyy format : " + date);
//Another Example of formatting Date in Java using SimpleDateFormat
DATE_FORMAT = new SimpleDateFormat("dd/MM/yy");
date = DATE_FORMAT.format(today);
System.out.println("Today in dd/MM/yy pattern : " + date);
//formatting Date with time information
DATE_FORMAT = new SimpleDateFormat("dd-MM-yy:HH:mm:SS");
date = DATE_FORMAT.format(today);
System.out.println("Today in dd-MM-yy:HH:mm:SS : " + date);
//SimpleDateFormat example - Date with timezone information
DATE_FORMAT = new SimpleDateFormat("dd-MM-yy:HH:mm:SS Z");
date = DATE_FORMAT.format(today);
System.out.println("Today in dd-MM-yy:HH:mm:SSZ : " + date);
From this site: http://www.java67.com/2013/01/how-to-format-date-in-java-simpledateformat-example.html#ixzz55Jw9BaXW
I am able to convert date to days using the below code.
SimpleDateFormat sfd = new SimpleDateFormat("yyyy-MM-dd");
String s1 = sfd.format(dateObj);
String a1 [] = s1.split("-");
int year = Integer.parseInt(a1[0].toString());
int month = Integer.parseInt(a1[1])-1;
int day = Integer.parseInt((a1[2]));
Calendar c1 = Calendar.getInstance();
c1.set(year,month,day);
days = c1.getTime().getTime()/(24*60*60*1000);
The above code works accurately in my system which is windows with timezone GMT +5.30.
However the same code in EST or Pacific timezone adds a day by 1 to final result when the time is 20.00 in the system.
What could be the issue ?
Do we need to set Timezone explicitly in the code ?
input dates does not hold any time stamp ..
is it correct to store in java.util.Date instead of java.sql.Date?
EDIT: As per Alex's comment, it's possible that the problems with the start of your code have blinded me to your real aim.
A Date represents an instant in time. That can fall on different dates depending on the time zone, but how do you want that to affect things? Do you want the number of days since the Unix epoch (which is always UTC) or the number of days since the 1st January 1970 in a particular time zone? Why do you want this "number of days" instead of a representation of a date such as LocalDate? What's the use case here?
EDIT: If you just want to know the number of days since the Unix epoch, you can skip most of this:
days = dateObj.getTime() / (24 * 60 * 60 * 1000);
You shouldn't be going through formatting at all just to get the year / month / day. Just create a Calendar, set the relevant time zone, call setTime with the dateObj you've already got, and then clear the hour/minute/second part of the calendar.
However, you should explicitly specify which time zone you want to consider - a Date represents an instant in time, which will mean different dates in different time zones.
You should also consider using Joda Time which makes all of this simpler and has a specific type for dates (LocalDate). That would also make it easy to find the number of days between the Unix epoch and a particular date without performing the division yourself.
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:
You can convert the object of java.util.Date to Instant using Date#toInstant and then you can find the number of days from now until this date using ChronoUnit#between.
Demo:
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.GregorianCalendar;
public class Main {
public static void main(String[] args) {
// A sample java.util.Date
Date dateObj = GregorianCalendar.from(ZonedDateTime.of(2021, 10, 2, 22, 25, 0, 0, ZoneOffset.UTC)).getTime();
Instant instant = dateObj.toInstant();
// Difference between now and the given java.util.Date
System.out.println(ChronoUnit.DAYS.between(Instant.now(), instant));
}
}
Output:
99
ONLINE DEMO
Note that the above code calculates the number of days between two moments/instants represented in UTC. If you have date-time values local to a particular timezone, you need to specify the corresponding ZoneId.
Demo:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.GregorianCalendar;
public class Main {
public static void main(String[] args) {
ZoneId tz = ZoneId.of("Australia/Brisbane");
// A sample java.util.Date representing the local date and time values in Australia/Brisbane
Date dateObj = GregorianCalendar.from(ZonedDateTime.of(2021, 10, 2, 22, 25, 0, 0, tz)).getTime();
// Difference between now in Australia/Brisbane and the given java.util.Date
System.out.println(ChronoUnit.DAYS.between(Instant.now().atZone(tz), dateObj.toInstant().atZone(tz)));
}
}
Output:
98
ONLINE DEMO
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 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.