I have the following timestamp stored in a long variable: 1471906800000 this stores the date 18/01/2017 00:00:00
I'm trying to create another timestamp that will contain the same date as stored in the first timestamp, but with the time being 23:59:59 -
I don't even know where to start
How could I achieve this in the most simple way possible in Java?
Thanks.
Using Calendar will help you:
long l = 1471906800000l;
Date date = new Date(l);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
l = calendar.calendar.getTimeInMillis();
Both of the other Answers use outmoded classes, now supplanted by the java.time classes.
Perhaps your input number is a count of milliseconds from the epoch of first moment of 1970 in UTC (1970-01-01T00:00:00Z). But I do not get the result you stated in the question.
long input = 1_471_906_800_000L ;
Instant instant = Instant.ofEpochMilli( input );
input: 1471906800000
instant: 2016-08-22T23:00:00Z
But you expected the value of 18/01/2017 00:00:00, off by a few months. If your input is not a count of milliseconds from 1970-01-01T00:00:00Z, you need to edit your Question to specify.
If you made a mistake in your expected output, then let's proceed to set the time-of-day.
If you wanted the second before the end of the day, I suggest subtracting a second from the start of the following day rather than hard-coding the time of 23:59:59. That time-of-day may be invalid because of anomalies such as Daylight Saving Time (DST). Also, unless you meant intend to work in UTC, you need to move into the desired/expected time zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
Extract a LocalDate, for a date-only value without time-of-day and without time zone.
LocalDate ld = zdt.toLocalDate();
Move to next day.
LocalDate ldNextDay = ld.plusDays( 1 );
Ask for first moment.
ZonedDateTime zdtNextDay = ldNextDay.atStartOfDay( z );
Subtract a second to move back into previous day.
ZonedDateTime zdtPreviousDay = zdtNextDay.minusSeconds( 1L );
However, I suspect you are taking the wrong approach to handling date-time values. Rather than trying to determine the end of a day, I strongly suggest you follow the common practice of using the Half-Open approach to spans of time. In Half-Open, the beginning is inclusive while the ending is exclusive.
So a full day starts with the first moment of one day and runs up to, but not including, the first moment of the next day. This way you avoid the problem of the last second or trying to get the infinitely divisible fraction of a second.
ZonedDateTime zdtDayStart = LocalDate.of( 2017 , Month.JANUARY , 18 ).atStartOfDay( 1 );
ZonedDateTime zdtDayStop = zdtDayStart.plusDays( 1 );
You may find the Interval class in the ThreeTen-Extra project helpful.
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 and 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 SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I'm assuming that you don't specifically want the time at 23:59:59, but rather a time 1 minute before the start of the next day.
You should use a date/time library. I know jodatime better, so this example is written using that, but you may be able to use the Java 8 time API instead.
DateTime today = new DateTime(1471906800000L, TIME_ZONE);
// You may want to check that today is actually at the start of the day.
// e.g. today.equals(today.withTimeAtStartOfDay());
DateTime lastMinuteOfToday =
today.toLocalDate()
.plusDays(1)
.toDateTimeAtStartOfDay(TIME_ZONE)
.minusMinutes(1);
long lastMinuteOfTodayMillis = lastMinuteOfToday.getMillis();
Knowing the timezone is important to do this correctly.
Related
I'm working on a project which takes rrule to generate next occurrences. But I'm not able to understand what i need to put in UNTIL tag of rrule.
String str="RRULE:FREQ=MONTHLY;UNTIL=20190625T000000Z;INTERVAL=2;";
Idk how to convert date into "20190625T000000Z".I'm using rfc 2445 java library. If user enters the date as a string for example :25/06/2019......i need to set this value in UNTIL tag as shown above. If I set the default value in UNTIL then it works but not when i make it user friendly.. I'm taking all the values from user as start date, end date, interval, Byday,Until... But idk what value to set in UNTIL.
If someone can help.. Thanks in advance.
Parsing basic ISO 8601 format
Your input 20190625T000000Z is the “basic” variation of standard ISO 8601 format to represent a moment in UTC. The word “basic” means minimizing the use of delimiters (I do not recommend this, as it makes the string less readable by humans).
Defining a formatting pattern to match input.
String input = "20190625T000000Z";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmssX" );
OffsetDateTime odt = OffsetDateTime.parse( input , f );
Dump to console.
System.out.println("odt.toString(): " + odt);
See this code run live at IdeOne.com.
odt.toString(): 2019-06-25T00:00Z
Translating date to moment
If user enters the date as a string for example :25/06/2019......i need to set this value in UNTIL tag as shown above
First, parse that input string into a LocalDate, representing a date-only value, without time-of-day and without time zone.
DateTimeFormatter fDateOnly = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
LocalDate ld = LocalDate.parse( "25/06/2019" , fDateOnly );
ld.toString(): 2019-06-25
As for translating that date into a moment (a date with time-of-day in a zone or offset-from-UTC), that is trickier than it sounds intuitively.
A date such as the 25th of June 2019 represents an entire day. And a theoretical date at that. The moments when a day begins and ends varies around the globe by time zone. A new day begins much earlier in Tokyo Japan than in Paris France, and even later in Montréal Québec.
Another issue is that the day does not always begin at 00:00:00. Because of anomalies such as Daylight Saving Time (DST), the first moment of a day on some dates in some zones may be something like 01:00:00. Let the java.time classes determine first moment.
ZoneId z = ZoneId.of( "Africa/Tunis" );
ZonedDateTime zdt = ld.atStartOfDay( z );
zdt.toString(): 2019-06-25T00:00+01:00[Africa/Tunis]
That ZonedDateTime object represents a specific moment. But it uses the wall-clock time adopted by the people of a particular region (a time zone). Your goal is a moment in UTC. Fortunately, we can adjust from the zone to UTC by converting to an OffsetDateTime (a date and time with a context of offset-from-UTC rather than a time zone). We can specify UTC (an offset of zero) by the ZoneOffset.UTC constant.
OffsetDateTime odt = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC );
odt.toString(): 2019-06-24T23:00Z
Note how 00:00 on the 25th in Tunisia is 11 PM “yesterday” the 24th in UTC. Same moment, same simultaneous point on the timeline, but two different wall-clock times.
Lastly, we need a string in that “basic” ISO 8601 format. Use the same formatter we defined above.
DateTimeFormatter fIso8601DateTimeBasic = DateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmssX" );
String output = odt.format( fIso8601DateTimeBasic );
output: 20190624T230000Z
See this code run live at IdeOne.com.
Just what is the difference between a time zone and an offset-from-UTC? An offset is merely a number of hours-minutes-seconds. Nothing more, nothing less, just a number (well, three numbers). A time zone is much more. A time zone is a history of past, present, and future changes to the offset used by the people of a particular region. For example, in most of North America, the offset changes twice a year, springing ahead an hour and then falling back an hour (the lunacy of Daylight Saving Time (DST)).
Tip: Date-time handling is surprisingly tricky and slippery. If you are working with calendars and the iCalendar spec for data exchange, I suggest you take a long while to study the concepts and practice with the industry-leading java.time classes.
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.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - 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
Most 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 (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
In the Java docs, Calendar.HOUR is supposed to return the hour in the 12 hour format, and Calendar.HOUR_OF_DAY is supposed to return the hour in the 24 hour format, but both of these are returning in the 12 hour format.
My Code:
Calendar rightNow = Calendar.getInstance();
int hour = rightNow.get(Calendar.HOUR_OF_DAY);
System.out.println("hour: " + hour);
There is a question that is similar to mine already, but there's is for a specific time and I'm attempting to do this with the current time. That question is here java HOUR and HOUR_OF_DAY both returning 12-hr time
EDIT:
If it matters, this is happening within Eclipse on Windows, within cmd.exe on Windows, and Terminal on Ubuntu.
EDIT 2
Now I feel dumb... I didn't realize that I had multiple instances of calling the current time, and I was looking at the wrong one, which was HOUR_OF_DAY, but the one I was seeing in the console were being posted by just HOUR... Thanks for the help in the comments and the edit of my own post that led me to realize my mistake
try this test
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR, 17);
System.out.println(c.get(Calendar.HOUR_OF_DAY));
System.out.println(c.get(Calendar.HOUR));
it prints
17
5
When setting the hour, its important to either use HOUR_OF_DAY and 24 hour notation, or use HOUR and supply the AM_PM field...
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 17);
System.out.println(c.get(Calendar.HOUR_OF_DAY));
System.out.println(c.get(Calendar.HOUR));
System.out.println(c.get(Calendar.AM_PM));
c.set(Calendar.HOUR_OF_DAY, 5);
System.out.println(c.get(Calendar.HOUR_OF_DAY));
System.out.println(c.get(Calendar.HOUR));
System.out.println(c.get(Calendar.AM_PM));
Will print...
17
5
1 // PM
5
5
0 // AM
When I use
c.set(Calendar.HOUR, 17);
System.out.println(c.get(Calendar.HOUR_OF_DAY));
System.out.println(c.get(Calendar.HOUR));
System.out.println(c.get(Calendar.AM_PM));
I get...
5
5
0 // AM
Which means the API has filtered the result and made an internal correction. It's VERY, important to use the right field for the right value as the Calendar can roll values as it sees fit...
If I add c.setLenient(false);, it will throw a java.lang.IllegalArgumentException: HOUR because 17 is not a valid value for HOUR
if you are running code at server side then stop server and then delete project from server and clean server after that your problem solved.
but if not then create a Test class:
public class Test {
public static void main(String[] args) {
Calendar calender = Calendar.getInstance();
System.out.println(calender.getTimeInMillis());
calender.set(Calendar.HOUR, 2);
System.out.println(calender.getTimeInMillis());
System.out.println(calender.get(Calendar.HOUR_OF_DAY));
System.out.println(calender.get(Calendar.HOUR_OF_DAY));
System.out.println(calender.get(Calendar.HOUR));
Calendar calender1 = Calendar.getInstance();
System.out.println(calender1.getTimeInMillis());
calender1.setTimeInMillis(calender.getTimeInMillis());
System.out.println(calender1.getTimeInMillis());
System.out.println(calender1.getTimeInMillis());
}}
then right click on class in eclipse and run as java application. then it works
I tried your source.
It can get right result.
Checking all the areas in my code that referenced the Calendar object to try to get the hours was the problem. I did this in three different locations but only modified one of the three, which is why my updates didn't seem to take effect
tl;dr
Instant.now()
.atZone( ZoneId.of( "America/New_York" ) )
.getHour()
Using java.time
You are using troublesome old legacy date-time classes now supplanted by the java.time classes.
Instant
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.
Get current moment:
Instant instant = Instant.now();
instant.toString(): 2016-09-16T20:46:01.123456789Z
ZonedDateTime
Time zone is crucial in determining the date and time-of-day. For any given moment, the date and the time-of-day vary around the globe by zone.
Apply a time zone to see some region’s wall-clock time.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
zdt.toString() 2016-09-16T16:46:01.123456789-04:00[America/Montreal]
Interrogate for time-of-day as a number 0-23.
int hourOfDay = zdt.gotHour();
16
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I found this funny behavior while using Date and Calendar class to handle Exponential distributions for simulating arrival time at a store (academic work). The code is quite simple and is below displayed. Well suppose that "this.currentDate" is "Feb 15 08:00:00 BRST 2014".
If i shift forward the time 24h (parameter iSeconds=86.400), what is supposed to return ? The expected string would be "2014-02-16 08:00:00" but instead the time is shortened in 1h and the result is "2014-02-16 07:00:00", I wonder if someone could explain why my one hour was "stolen". No big deal, but since my next arrival time depends of the earlier one, it makes a mess over my time baseline shifting all of them one hour as well.
I thought could be some TZ issue, but heck, i just moved 24h in the middle of February.
public String shiftTimeStamp( int iSeconds)
{
Calendar cal = Calendar.getInstance();
cal.setTime(this.currentDate);
cal.add(Calendar.SECOND, iSeconds);
this.currentDate = cal.getTime();
String sTS = new SimpleDateFormat(SCSimLabels.DATE_TS_FORMAT).format(this.currentDate);
return sTS;
}
Note: Daylight Saving Time issue :) BRT <--> BRST tz.
my workaround: I just want a beacon to guide the time jumps caused by inter arrival times and I´m not interested on such calendar specificities, so when I need to move to the first work hour of the next day I just force the time to be 08:00:00 after 1 day shift. It works like a charm :)
Calendar cal = Calendar.getInstance();
cal.setTime(this.currentDate);
cal.add(Calendar.DATE, 1);
String sDate = (new SimpleDateFormat("yyyy-MM-dd 08:00:00")).format(cal.getTime());
Date newDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(sDate);
this.currentDate = newDate;
Change the format call to this:
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(this.currentDate);
To see what timezone the format call is using. I bet the call to .add() is modifying the Calendar object's timezone since it crosses the standard time / daylight time border.
If this is the case, you could try adding a Calendar.DAY,1 or simply .setTimeZone(...) of the Calendar obj. back to the original timezone after the .add call.
Avoid legacy date-time classes
You are using troublesome old date-time classes that are now legacy, supplanted by the java.time classes.
Using java.time
If you want to work with generic 24-hour days without any time zone or offset-from-UTC, use the LocalDateTime class. If you always want to start at 8 AM, specify a LocalTime.
LocalDate ld = LocalDate.of( 2014 , Month.FEBRUARY , 15 ) ;
LocalTime lt = LocalTime.of( 8 , 0 ) ; // Specify hour in 24-hour clock, 0-23.
LocalDateTime ldt = LocalDateTime.of( ld , lt );
Represent your 24 hour span as a Duration.
Duration d = Duration.ofHours( 24 );
LocalDateTime ldtLater = ldt.plus( d );
If you want to work with specific moments on the timeline as seen through the lens of a region’s particular wall-clock time, then specify a ZoneId to get a ZonedDateTime.
ZoneId z = ZoneId.of( "America/Sao_Paulo" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
ZonedDateTime zdtLater = zdt.plus( d );
Note that adding 24 hours to a ZonedDateTime is not the same thing as adding a day. As you have learned the hard way, anomalies such as Daylight Saving Time (DST) means a day may be 23, 24, or 25 hours long, or even other lengths. So if you want to add a day and let java.time apply its logic to arrive at an appropriate time-of-day while taking into consideration anomalies such as DST, add days rather than hours.
ZonedDateTime zdtLater = zdt.plusDays( 1 );
Or add a Period of one whole day rather than a Duration of 24 hours.
Period p = Period.ofDays( 1 );
ZonedDateTime zdtLater = zdt.plus( p );
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
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I store a number of rows in DB with the timestamp of that moment in milliseconds.
Now if I need to retrieve all rows of a given day, like today, how do I correctly create the starting and ending milliseconds of that day?
I know about SimpleDateFormat and Calendar.getInstance() briefly, but would I need to do string manipulation (which I want to avoid) to get todays date only, add the hours part and then convert it back into milliseconds, or is there a better way to do it?
Since you didn't provide any code in your question, please allow me to give you a general answer in response..
What you're looking for are two date/times, today and tomorrow, both specified a "0 hours, 0 minutes, 0 seconds".
today <= date AND date < tomorrow
Note the two different comparisons.
The simplest technique would be to use DateFormat:
String input = "Sat Feb 17 2013";
Date date = new SimpleDateFormat("EEE MMM dd yyyy", Locale.ENGLISH).parse(input);
long milliseconds = date.getTime();
String input1="Sun Feb 18 2013"
Date inputNextDay = new SimpleDateFormat("EEE MMM dd yyyy", Locale.ENGLISH).parse(input);
long millisecondsForNextDay=inputNextDay.getTime();
To get the rows that fall on a particular day, just find rows having milliseconds value of timestamp between milliseconds and millisecondsForNextDay:
if(rowsTimestampSeconds>milliseconds && rowsTimestampSeconds<millisecondsForNextDay){
//get the row
}
You can use the GregorianCalendar class to do this without any strings.
Calendar calendar = new GregorianCalendar(year, month, day);
long start_of_day_millis = calendar.getTimeInMillis();
calendar.add(Calendar.DAY_OF_MONTH, 1);
long next_day_millis = calendar.getTimeInMillis();
The reason to use calendar.add(Calendar.DAY_OF_MONTH); instead of just adding (24*60*60*1000) to the first millisecond value is to account for leaps. Beyond the commonly known leap year, there are occurrences of leap seconds. See this link: http://www.timeanddate.com/time/leapseconds.html
Make sure that your expression is inclusive of start_of_day_millis (greater than or equal) and exlusive of next_day_millis (lesser than).
i.e: if(test_time >= start_of_day_millis && test_time < next_day_millis)
Update:
If you want today's date you can omit all the parameters in the calendar constructor and just call new GregorianCalendar(), but you will need to ensure that the hour, minute, second and millisecond fields are being zeroed out with calls to calendar.set(Calendar._FIELD_NAME_, 0); afterwards, before you use the calendar, because it would be initialized to the exact moment the object is created.
You should be using a date-time type for your database column to store date-time data rather than an integer of milliseconds. The SQL standard defines a few date-time types. But support for date-time varies widely, with Postgres being one of the best.
Since you tagged Java, read this Question and my Answer to learn about using Java to pinpoint the first moment of today and tomorrow. The Half-Open approach used there is common in date-time work. Half-Open means a span of time where the beginning is inclusive while the ending is exclusive. For SQL, it means not using the BETWEEN operator.
java.time
The java.time framework is built into Java 8 and later, and back-ported to Java 6 & 7 and to Android. Read my other Answer for details.
Get the first moments of today and tomorrow. Be aware that time zone is crucial in determining dates and the meaning of “today”. For any given moment, the date varies around the world by time zone. A new day begins earlier in the east. For example, a few moments after midnight in Paris is still “yesterday” in Montréal.
Instant instant = Instant.now();
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );
ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );
Some day we may see JDBC drivers updated to directly handle java.time types. Indeed, JDBC 4.2 compliant drivers may work if you call getObject and setObject on your ResultSet and PreparedStatement respectively. But if not, fallback to using the java.sql types. Notice the new methods added to these old classes including java.sql.Timestamp. The from method takes an Instant which we can extract from our ZonedDateTime objects.
java.sql.Timestamp tsStart = java.sql.Timestamp.from( zdtStart.toInstant() );
java.sql.Timestamp tsStop = java.sql.Timestamp.from( zdtTomorrowStart.toInstant() );
Now set these two variables are arguments on your PreparedStatement. Notice the comparison operators, testing for possible values that start on first moment of the day (>=) and running up to but not including the first moment of the next day (<).
String sql =
"SELECT * FROM event_" +
"WHERE when_ >= ? " +
"AND when_ < ? " +
";" ;
…
pstmt.setTimestamp( 1 , tsStart );
pstmt.setTimestamp( 2 , tsStop );
If you do indeed store integers instead of using date-time types, and you are storing milliseconds as a count from the epoch reference date-time of first moment of 1970 in UTC, then you can extract a number from each Instant. Remember that the java.time classes use a finer resolution of nanoseconds as do some databases such as H2 Database, and some databases such as Postgres capture date-time with a resolution of microseconds. So truncating to milliseconds may mean a loss of data.
long millisStart = tsStart.toInstant().toEpochMilli();
long millisStop = tsStop.toInstant().toEpochMilli();
Call setLong on your PreparedStatement.
pstmt.setLong( 1 , millisStart );
pstmt.setLong( 2 , millisStop );
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - 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
Most 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 (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I need to get the dates for Monday and Friday last week. To do this, i am getting the date of Monday this week and subtracting 7 days. This gives me the date for Monday last week.
To get the date for Friday i have to add 4. This confused me a bit because for some reason the first day of the week is Sunday as opposed to Monday here in the UK.
Anyway, here is how i am getting the dates.
// Get the dates for last MON & FRI
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
cal.add(Calendar.DAY_OF_WEEK, -7);
cal.set(Calendar.HOUR_OF_DAY,0);
cal.set(Calendar.MINUTE,0);
cal.set(Calendar.SECOND,0);
cal.set(Calendar.MILLISECOND,0);
// Get the date on Friday
cal.add(Calendar.DAY_OF_WEEK, 4);
cal.set(Calendar.HOUR_OF_DAY,23);
cal.set(Calendar.MINUTE,59);
cal.set(Calendar.SECOND,59);
cal.set(Calendar.MILLISECOND,0);
The above works but i am interested if there is anything wrong with the logic. I.e. will it work for Februarys, leap years etc.
Feel free to suggest a better solution/approach.
Thanks
tl;dr
get the dates for Monday and Friday last week
LocalDate // Represent a date only, without a time-of-day, and without a time zone or offset.
.now // Capture the current date as seen through the wall-clock time used by the people of a certain region (a time zone).
(
ZoneId.of( "America/Montreal" )
) // Returns a `LocalDate` object.
.with // Move to another date.
(
TemporalAdjusters.previous( DayOfWeek.MONDAY ) // Returns an implementation of the `TemporalAdjuster` interface.
) // Returns another `LocalDate` object, separate and distinct from our original `LocalDate` object. Per the immutable objects design pattern.
Avoid legacy date-time classes
The other Answers use the troublesome old legacy date-time classes now supplanted by the java.time questions.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
ZoneId z = ZoneId.of( “America/Montreal” );
LocalDate today = LocalDate.now( z );
TemporalAdjuster
The TemporalAdjuster interface provides for adjustments to move from one date-time value to another. Find handy implementations in the TemporalAdjusters class (note the plural 's'). The previous adjuster finds any specified object from the DayOfWeek enum.
The Question does not exactly define “last week”. Last seven days? Standard Monday-Sunday period? Localized week, such as Sunday-Saturday in the United States? The week prior to today’s week or including today’s partial week?
I will assume the prior seven days were intended.
LocalDate previousMonday = today.with( TemporalAdjusters.previous( DayOfWeek.MONDAY ) ) ;
LocalDate previousFriday = today.with( TemporalAdjusters.previous( DayOfWeek.FRIDAY ) ) ;
By the way, if you want to consider the initial date if it happens to already be the desired day-of-week, use alternate TemporalAdjuster implementations: previousOrSame or nextOrSame.
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
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 (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Note: For Java 8 and above please take a look at Basil Bourque's answer (link).
Java 8 introduced a new time/date API which offers most of Joda-Time's functionality.
Joda-Time offers really nice methods for problems like that.
Getting the dates for Monday and Friday last week would look something like this using Joda Time:
DateTime today = DateTime.now();
DateTime sameDayLastWeek = today.minusWeeks(1);
DateTime mondayLastWeek = sameDayLastWeek.withDayOfWeek(DateTimeConstants.MONDAY);
DateTime fridayLastWeek = sameDayLastWeek.withDayOfWeek(DateTimeConstants.FRIDAY);
You can create DateTime objects from java.util.Date objects and vice versa so it is easy to use with Java dates.
Using the above code with the date
DateTime today = new DateTime("2012-09-30");
results in "2012-09-17" for Monday and "2012-09-21" for Friday, setting the date to
DateTime tomorrow = new DateTime("2012-10-01");
results in "2012-09-24" for Monday and "2012-09-28" for Friday.
You still have start of week set to sunday, which means that Calendar.MONDAY on a saturday is the monday before, while Calendar.MONDAY on a sunday is the next day.
What you need to do is (according to how you want it according to your comment above), to set the start of week to monday.
Calendar cal = Calendar.getInstance();
cal.setFirstDayOfWeek(Calendar.MONDAY);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
cal.add(Calendar.DAY_OF_WEEK, -7);
...
Beyond that, and that the last second of friday isn't included in the range, your logic seems sound, and shouldn't have trouble with leap years/DST shifts etc.
The only thing I see wrong is that you are in fact testing the range Mo-Fr, and not, as stated, retrieving two specific days. It would be safer to test range Mo-Sa with exclusive upper bound.
You can use TemporalAdjusters to adjust the desired dates/days you are looking for.
Example:
LocalDate today = LocalDate.now();
LocalDate lastMonday = today.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
LocalDate lastFriday = today.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));