How to get the first day of the current week and month? How to get the first day of the current week and month? android android

How to get the first day of the current week and month?


This week in milliseconds:

// get today and clear time of dayCalendar cal = Calendar.getInstance();cal.set(Calendar.HOUR_OF_DAY, 0); // ! clear would not reset the hour of day !cal.clear(Calendar.MINUTE);cal.clear(Calendar.SECOND);cal.clear(Calendar.MILLISECOND);// get start of this week in millisecondscal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());System.out.println("Start of this week:       " + cal.getTime());System.out.println("... in milliseconds:      " + cal.getTimeInMillis());// start of the next weekcal.add(Calendar.WEEK_OF_YEAR, 1);System.out.println("Start of the next week:   " + cal.getTime());System.out.println("... in milliseconds:      " + cal.getTimeInMillis());

This month in milliseconds:

// get today and clear time of dayCalendar cal = Calendar.getInstance();cal.set(Calendar.HOUR_OF_DAY, 0); // ! clear would not reset the hour of day !cal.clear(Calendar.MINUTE);cal.clear(Calendar.SECOND);cal.clear(Calendar.MILLISECOND);// get start of the monthcal.set(Calendar.DAY_OF_MONTH, 1);System.out.println("Start of the month:       " + cal.getTime());System.out.println("... in milliseconds:      " + cal.getTimeInMillis());// get start of the next monthcal.add(Calendar.MONTH, 1);System.out.println("Start of the next month:  " + cal.getTime());System.out.println("... in milliseconds:      " + cal.getTimeInMillis());


The first day of week can be determined with help of java.util.Calendar as follows:

Calendar calendar = Calendar.getInstance();calendar.clear();calendar.setTimeInMillis(timestamp);while (calendar.get(Calendar.DAY_OF_WEEK) > calendar.getFirstDayOfWeek()) {    calendar.add(Calendar.DATE, -1); // Substract 1 day until first day of week.}long firstDayOfWeekTimestamp = calendar.getTimeInMillis();

The first day of month can be determined as follows:

Calendar calendar = Calendar.getInstance();calendar.clear();calendar.setTimeInMillis(timestamp);while (calendar.get(Calendar.DATE) > 1) {    calendar.add(Calendar.DATE, -1); // Substract 1 day until first day of month.}long firstDayOfMonthTimestamp = calendar.getTimeInMillis();

Pretty verbose, yes.


Java 7 will come with a much improved Date and Time API (JSR-310). If you can't switch yet, then you can as far use JodaTime which makes it all less complicated:

DateTime dateTime = new DateTime(timestamp);long firstDayOfWeekTimestamp = dateTime.withDayOfWeek(1).getMillis();

and

DateTime dateTime = new DateTime(timestamp);long firstDayOfMonthTimestamp = dateTime.withDayOfMonth(1).getMillis();


java.time

The java.time framework in Java 8 and later supplants the old java.util.Date/.Calendar classes. The old classes have proven to be troublesome, confusing, and flawed. Avoid them.

The java.time framework is inspired by the highly-successful Joda-Time library, defined by JSR 310, extended by the ThreeTen-Extra project, and explained in the Tutorial.

Instant

The Instant class represents a moment on the timeline in UTC.

The java.time framework has a resolution of nanoseconds, or 9 digits of a fractional second. Milliseconds is only 3 digits of a fractional second. Because millisecond resolution is common, java.time includes a handy factory method.

long millisecondsSinceEpoch = 1446959825213L;Instant instant = Instant.ofEpochMilli ( millisecondsSinceEpoch );

millisecondsSinceEpoch: 1446959825213 is instant: 2015-11-08T05:17:05.213Z

ZonedDateTime

To consider current week and current month, we need to apply a particular time zone.

ZoneId zoneId = ZoneId.of ( "America/Montreal" );ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );

In zoneId: America/Montreal that is: 2015-11-08T00:17:05.213-05:00[America/Montreal]

Half-Open

In date-time work, we commonly use the Half-Open approach to defining a span of time. The beginning is inclusive while the ending in exclusive. Rather than try to determine the last split-second of the end of the week (or month), we get the first moment of the following week (or month). So a week runs from the first moment of Monday and goes up to but not including the first moment of the following Monday.

Let's the first day of the week, and last. The java.time framework includes a tool for that, the with method and the ChronoField enum.

By default, java.time uses the ISO 8601 standard. So Monday is the first day of the week (1) and Sunday is last (7).

ZonedDateTime firstOfWeek = zdt.with ( ChronoField.DAY_OF_WEEK , 1 ); // ISO 8601, Monday is first day of week.ZonedDateTime firstOfNextWeek = firstOfWeek.plusWeeks ( 1 );

That week runs from: 2015-11-02T00:17:05.213-05:00[America/Montreal] to 2015-11-09T00:17:05.213-05:00[America/Montreal]

Oops! Look at the time-of-day on those values. We want the first moment of the day. The first moment of the day is not always 00:00:00.000 because of Daylight Saving Time (DST) or other anomalies. So we should let java.time make the adjustment on our behalf. To do that, we must go through the LocalDate class.

ZonedDateTime firstOfWeek = zdt.with ( ChronoField.DAY_OF_WEEK , 1 ); // ISO 8601, Monday is first day of week.firstOfWeek = firstOfWeek.toLocalDate ().atStartOfDay ( zoneId );ZonedDateTime firstOfNextWeek = firstOfWeek.plusWeeks ( 1 );

That week runs from: 2015-11-02T00:00-05:00[America/Montreal] to 2015-11-09T00:00-05:00[America/Montreal]

And same for the month.

ZonedDateTime firstOfMonth = zdt.with ( ChronoField.DAY_OF_MONTH , 1 );firstOfMonth = firstOfMonth.toLocalDate ().atStartOfDay ( zoneId );ZonedDateTime firstOfNextMonth = firstOfMonth.plusMonths ( 1 );

That month runs from: 2015-11-01T00:00-04:00[America/Montreal] to 2015-12-01T00:00-05:00[America/Montreal]

YearMonth

Another way to see if a pair of moments are in the same month is to check for the same YearMonth value.

For example, assuming thisZdt and thatZdt are both ZonedDateTime objects:

boolean inSameMonth = YearMonth.from( thisZdt ).equals( YearMonth.from( thatZdt ) ) ;

Milliseconds

I strongly recommend against doing your date-time work in milliseconds-from-epoch. That is indeed the way date-time classes tend to work internally, but we have the classes for a reason. Handling a count-from-epoch is clumsy as the values are not intelligible by humans so debugging and logging is difficult and error-prone. And, as we've already seen, different resolutions may be in play; old Java classes and Joda-Time library use milliseconds, while databases like Postgres use microseconds, and now java.time uses nanoseconds.

Would you handle text as bits, or do you let classes such as String, StringBuffer, and StringBuilder handle such details?

But if you insist, from a ZonedDateTime get an Instant, and from that get a milliseconds-count-from-epoch. But keep in mind this call can mean loss of data. Any microseconds or nanoseconds that you might have in your ZonedDateTime/Instant will be truncated (lost).

long millis = firstOfWeek.toInstant().toEpochMilli();  // Possible data loss.

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?