I wish to get the exact date of first day of last month at 00:00:00Z.
So, here is my current solution:
public static String getStartingDateAndTimeOfLastMonth() {
int dayOfCurrentMonth = ZonedDateTime.now().getDayOfMonth();
return ZonedDateTime.now()
.minusDays(dayOfCurrentMonth - 1)
.minusMonths(1)
.format(DateTimeFormatter.ISO_INSTANT);
}
When i call the moethod:
String startDate = CustomUtilsFunctions.getStartingDateAndTimeOfLastMonth();
System.out.println("startDate: " + startDate);
The output of current solution is:
startDate: 2021-05-01T07:22:10.389Z
As you can see, the time of the output is 07:22:10.389Z but, I don't know the easiest way to turn it to 00:00:00:000Z
So the desired output for is:
startDate: 2021-05-01T00:00:00.000Z
Point:
I know, i can extract the hour, minutes and seconds and millis and then use the minus(), but I believe there must be an easier solution.
Instead of using today as base, you could use a java.time.YearMonth (like this month) and subtract one month to get the last one. Then take the start of its first day. Do all that in UTC and then format as desired:
public static String getStartingDateAndTimeOfLastMonth() {
// get the current month and subtract one to get the last
YearMonth lastMonth = YearMonth.now().minusMonths(1);
// then return its first day
return lastMonth.atDay(1)
// at the beginning of the day in UTC
.atStartOfDay(ZoneOffset.UTC)
// formatted as desired
.format(
DateTimeFormatter.ofPattern(
"uuuu-MM-dd'T'HH:mm:ss.SSSX",
Locale.ENGLISH
)
);
}
This outputs today (10th of June, 2021):
2021-05-01T00:00:00.000Z
Note: The default format of ZonedDateTime omits seconds and fraction-of-second if they are zero.
If you are fine with 2021-05-01T00:00Z, you can replace
.format(
DateTimeFormatter.ofPattern(
"uuuu-MM-dd'T'HH:mm:ss.SSSX",
Locale.ENGLISH
)
);
with simply .toString();.
You could first create the desired day and then use it together with a set time to compose DateTime. Depending on your use case, you could use LocalDateTime or ZonedDateTime.
LocalDate day = LocalDate.now()
.minusMonths(1)
.withDayOfMonth(1);
ZonedDateTime target = ZonedDateTime.of(day, LocalTime.MIDNIGHT, ZoneId.systemDefault());
System.out.println(target);
Another option would be to use turncatedTo (as #Thomas mentioned in comment)
ZonedDateTime target = ZonedDateTime.now()
.minusMonths(1)
.withDayOfMonth(1)
.truncatedTo(ChronoUnit.DAYS)
.withZoneSameLocal(ZoneId.of("UTC")); // optional depending on your case
Related
Given a week number and a year, I'd like to be able to compute the first Sunday of that month. I've cobbled together some code that "mostly", but not always, works. Not sure why it doesn't work for every example, but that's why I'm posting. :)
The code below should get the first Sunday of the year, then iterate the number of weeks (the week number) entered. When done, the code should print out that first Sunday's date.
When incorrect, the code prints the previous Sunday, not the apparently correct one.
Suggestions appreciated.
public static void main(String[] args) throws IOException, MessagingException
{
int enteredWeekNumber = 18;
int enteredYear = 2022;
int doyCounter = 1;
LocalDate firstDoy = LocalDate.of(enteredYear, Month.JANUARY, 1);
LocalDate someSunday = firstDoy.with(firstInMonth(DayOfWeek.SUNDAY));
// Loop to get every Sunday by adding Period.ofDays(7) the current Sunday.
while (someSunday.getYear() == enteredYear && doyCounter <= enteredWeekNumber)
{
System.out.println(" *** " + someSunday.
format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)));
someSunday = someSunday.plus(Period.ofDays(7));
doyCounter++;
}
}
tl;dr
org.threeten.extra.YearWeek // Represents a week-based year and week per the ISO 8601 definition.
.of( y , w ) // Pass your week-based year number, and your week (0-52, 0-53).
.atDay( DayOfWeek.MONDAY ) // Returns `LocalDate`, for the date of the first day (Monday) of that year-week.
.with ( // Adjust to another `LocalDate` object, another date.
TemporalAdjusters // Utility class offering implementations of `TemporalAdjuster` interface.
.dayOfWeekInMonth(
1 , // nth day in the month, an ordinal number.
DayOfWeek.SUNDAY // The day-of-week for which we want the date of the nth.
) // Returns an `TemporalAdjuster` object.
) // Returns a `LocalDate` object.
ISO 8601
The ISO 8601 standard defines a year-week as:
Starting on a Monday.
Week # 1 containing the first Thursday of the calendar year.
This means a week-based year:
Has either 52 or 53 complete weeks.
May include a few days from the previous and/or next calendar year.
ThreeTen-Extra
If your definition is the same, then I suggest adding the Three-Ten Extra library to your project.
YearWeek
Doing so gives you access to the YearWeek class.
YearWeek yw = YearWeek.of( y , w ) ;
Tip: Pass around your codebase objects of this class rather than mere int values enteredWeekNumber & enteredYear. Using objects brings type-safety, ensures valid values, and makes your code more self-documenting.
LocalDate
Get the date of the first day of that week.
LocalDate ld = yw.atDay( DayOfWeek.MONDAY ) ;
TemporalAdjuster
Use a TemporalAdjuster to get nth day-of-week of that month date’s month.
Fortunately, the utility class TemporalAdjusters gives us just such an adjuster.
TemporalAdjuster ta = TemporalAdjusters.dayOfWeekInMonth( 1 , DayOfWeek.SUNDAY ) ;
Apply the temporal adjuster to get another LocalDate object. The java.time classes use immutable objects. We get a fresh object rather than altering ("mutating") the original.
LocalDate firstSunday = ld.with( ta ) ;
If you want to get fancy, you could write your own implementation of a TemporalAdjuster to contain this functionality. I’ll leave that as an exercise for the reader.
May be you could try something like below if your Week starts at the first day of the year
int enteredWeekNumber = 22;
int enteredYear = 2022;
LocalDate someSunday = LocalDate.now()
.withYear(enteredYear)
.with(ChronoField.ALIGNED_WEEK_OF_YEAR, enteredWeekNumber)
.with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY));
or somthing like below, if you use ISO standard
LocalDate someSunday2 = LocalDate.now()
.withYear(enteredYear)
.with(WeekFields.ISO.weekOfYear(), enteredWeekNumber)
.with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY));
I have:
a joda LocalDate, so it has no time information and just date
a string which contains time and zone information, like "14:20 CEST"
Either of them can be absent (Scala's Option).
How can I combine these two to get joda LocalDateTime, i.e. entity representing only date and time with no timezone?
To combine these 2 options, the natural way is to use flatMap method like this:
val onlyDateOption: Option[LocalDate] = ???
val timeAndZoneOption: Option[String] = ???
val result: Option[LocalDateTime] = onlyDateOption.flatMap { onlyDate =>
timeAndZoneOption.map { timeAndZone =>
// Some logic here to build the LocalDateTime from onlyDate and timeAndZone
}
}
Which can also be written with for-comprehension in more readible way:
val result: Option[LocalDateTime] = for {
onlyDate <- onlyDateOption
timeAndZone <- timeAndZoneOption
} yield {
// Some logic here to build the LocalDateTime from onlyDate and timeAndZone
}
Now, how to use Joda to build what you're expecting can probably be done in various different ways, one could be:
onlyDate
.toLocalDateTime(LocalTime.MIDNIGHT)
.withHourOfDay(...) // hour extracted from the string somehow
.withMinuteOfHour(...) // minute extracted from the string somehow
I'm not familiar with Joda API, there is probably another easier way
How to combine LocalDate and String using Joda-Time
You have already got an answer treating the use of Option in detail. Here I want to go into more detail with the combination of your LocalDate and your String into a LocalDateTime using Joda-Time. I understand that you are getting a Joda-Time LocalDate from legacy code and need to return a Joda-Time LocalDateTime to legacy code. I am assuming that you know the time zone the abbreviation of which is in the string. I think that you should validate that abbreviation since Central European Time uses the abbreviation CET during the standard time part of the year and CEST during summer time (DST). Excuse my Java code.
DateTimeUtils.setDefaultTimeZoneNames(createTimeZoneNamesMap());
DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("H:mm z");
LocalDate date = new LocalDate(2021, 5, 22);
String timeAndZoneString = "14:20 CEST";
LocalTime time = LocalTime.parse(timeAndZoneString, timeFormatter);
DateTime dateTime = date.toDateTime(time, ZONE);
// Validate time zone abbreviation; take overlap at fall-back into account
String earlierCorrectTimeString = dateTime.withEarlierOffsetAtOverlap()
.toString(timeFormatter);
if (! timeAndZoneString.equals(earlierCorrectTimeString)) {
String laterCorrectTimeString = dateTime.withLaterOffsetAtOverlap()
.toString(timeFormatter);
if (! timeAndZoneString.equals(laterCorrectTimeString)) {
throw new IllegalStateException("Incorrect time zone abbreviation for date");
}
}
LocalDateTime ldt = dateTime.toLocalDateTime();
System.out.println(ldt);
Output:
2021-05-22T14:20:00.000
I have used these two auxiliary declaration:
private static final DateTimeZone ZONE = DateTimeZone.forID("Europe/Paris");
private static Map<String, DateTimeZone> createTimeZoneNamesMap() {
Map<String, DateTimeZone> names = new HashMap<>(4);
names.put("CET", ZONE);
names.put("CEST", ZONE);
return names;
}
The validity of the time on the date is also validated: date.toDateTime() validates that the resulting DateTime would not fall in the gap at the spring-forward and throws an IllegalInstantException: if it would.
If the hours you receive in the string are always two digits, the format pattern string needs to specify this, so HH:mm z.
Please be aware that you are losing information in a corner case: If the time falls in the overlap at fall-back, the time zone abbreviation disambiguates, but the LocalDateTime that you produce is ambiguous. For example the date is 2021-10-31 and the time string is 2:20 CEST. Then we know that the time is in the summer time part of the year, that is, before the clocks are turned back. You return 2021-10-31T02:20:00.000, and the receiver won’t be able to tell whether to understand it as 2021-10-31T02:20:00.000+02:00 (summer time) or 2021-10-31T02:20:00.000+01:00 (standard time).
my method accepts - hours, minutes, seconds and milliseconds separated by sign / as a string parameter
how can I add to the current date the parameters that come to the method.
Example 1: today, 02/10/2021, the method receives metnode data (10/10/10/10) - output - 02/10/2021 10:10:10
Example 2: today, 02/10/2021, the method receives metnode data (55/10/10/10) - output - 02/12/2021 07:10:10
That is, you need to add 55 hours 10 seconds 10 seconds and 10 milliseconds to the current date.
you cannot use the Calendar and StringTokenizer classes.
public void method(String s) {
s = s.replaceAll("/", "-");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
final LocalDateTime now = LocalDateTime.parse(s, formatter.withResolverStyle(ResolverStyle.LENIENT));
System.out.println(now);
}
i found the withResolverStyle (ResolverStyle.LENIENT) method
but did not understand how to use it.
A lenient DateTimeFormatter is enough
I don’t know if it’s the best solution. That probably depends on taste. It does use the ResolverStyle.LENIENT that you mentioned and generally works along the lines of the code in your question, only fixed and slightly simplified.
My formatter includes both date and time. This is necessary for surplus hours to be converted to days.
private static final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd H/m/s/")
.appendValue(ChronoField.MILLI_OF_SECOND)
.toFormatter()
.withResolverStyle(ResolverStyle.LENIENT);
Next thing we need a string that matches the formatter. So let’s prepend the date to the time string that we already have got:
String timeString = "55/10/10/10";
LocalDate today = LocalDate.now(ZoneId.of("America/Regina"));
String dateTimeString = "" + today + ' ' + timeString;
LocalDateTime dateTime = LocalDateTime.parse(dateTimeString, formatter);
System.out.println(dateTime);
The output from my code when I ran it today (February 10) was:
2021-02-12T07:10:10.010
A different idea: use Duration
Edit: An alternative is to use the Duration class. A reason for doing that would be that it really appears that you are adding a duration rather than setting the time of day. A liability is that parsing your string into a Duration is a bit tricky. The Duration.parse method that we want to use only accepts ISO 8601 format. It goes like PT55H10M10.010S for a period of time of 55 hours 10 minutes 10.010 seconds. And yes, milliseconds need to be given as a fraction of the seconds.
String isoTimeString = timeString.replaceFirst("(/)(\\d+)$", "$100$2")
.replaceFirst("(\\d+)/(\\d+)/(\\d+)/0*(\\d{3})", "PT$1H$2M$3.$4S");
Duration dur = Duration.parse(isoTimeString);
LocalDateTime dateTime = LocalDate.now(ZoneId.of("Asia/Kathmandu"))
.atStartOfDay()
.plus(dur);
When I ran it just now — already February 11 in Kathmandu, Nepal — the output was:
2021-02-13T07:10:10.010
I am using two calls to replaceFirst(), each time using a regular expression. The first call simply adds some leading zeroes to the milliseconds. $1 and $2 in the replacement string give us what was matched by the first and the second group denoted with round brackets in the regular expression.
The second replaceFirst() call established the ISO 8601 format, which includes making sure that the milliseconds are exactly three digits so they work as a decimal fraction of the seconds.
Link: ISO 8601
Try this:
public void method(String s) {
String[] arr = s.split("/");
LocalDateTime now = LocalDateTime.of(
LocalDate.now(), LocalTime.of(0, 0))
.plusHours(Integer.parseInt(arr[0]))
.plusMinutes(Integer.parseInt(arr[1]))
.plusSeconds(Integer.parseInt(arr[2]))
.plusNanos(Integer.parseInt(arr[3]) * 1_000_000L);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");
System.out.println(now.format(formatter));
}
Look into the LocalDateTime documentation. It offers various means for combining dates. Such as:
plus(amount, unit)
plusDays(days)
plusHours(hours)
plusMinutes(minutes)
just for simplicity , you can your LocalDateTime class. it is easy to understand. please refer to below code is used to add the hours, minuts, second and nanos to current Date Time.
this Date Time then can easy formatted by any format pattern as required.
public void addDateTime(int hours, int minuts, int seconds, int nanos) {
LocalDateTime adt = LocalDateTime.now();
System.out.println(adt);
adt = adt.plusHours(hours);
adt = adt.plusMinutes(minuts);
adt = adt.plusSeconds(seconds);
adt = adt.plusNanos(nanos);
System.out.println(adt);
}
First I get:
LocalDate today = LocalDate.now();
and second
Date date = new Date();
date.setDate(Integer.valueOf(s[0]));
date.setMonth(Integer.valueOf(s[1]));
date.setYear(Integer.valueOf(s[2]));
LocalDate topicDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
How to check whether the differences between the first date and the second is 7 days?
For example, today is 03-08-2015 and the second date is 20-07-2015 and the difference between is more than 7 days, but how to check this?
Should I convert date to millisecond?
I Believe that is still the best way at the moment.
You can view some insights on the subject here:
Calculate date/time difference in java
You could convert to milliseconds or you could individually check if the year was larger, then if they are the same check to see if the month is larger then check day. Converting to milliseconds would be very easy though.
I believe you are looking for something like this:
Date date = /*your date object you want to compare*/;
Instant now = Instant.now();
Instant sevenDaysFromYourDate = Instant.ofEpochMilli(date.getTime()).plus(Duration.ofDays(7));
if (now.isAfter(sevenDaysFromYourDate)) {
//today is more than seven days past date
}
LocalDate today = LocalDate.now();
if (topicDate.isAfter(today.plusDays(7))) {
System.out.println("Yes");
}
else {
System.out.println("No");
}
Since you are using Java 8 LocalDate, you can use the plusDays or minusDays methods of the LocalDate class.
Furthermore, you shouldn't be using an (old, not recommended for use) java.util.Date object to create your second date. It's better to use LocalDate.of which builds a date from the year, month and day.
Example code:
LocalDate today = LocalDate.now();
LocalDate topicDate = LocalDate.of(
Integer.valueOf(s[2]),
Integer.valueOf(s[1]),
Integer.valueOf(s[0]));
System.out.println(today);
System.out.println(topicDate);
if ( today.minusDays(7).equals(topicDate)) {
System.out.println( "Exactly a week difference between today and topicDate");
} else if ( today.minusDays(7).compareTo(topicDate) > 0 ) {
System.out.println("TopicDate is more than a week before today");
} else {
System.out.println("TopicDate is less than a week before today");
}
Note that you can use the compareTo for exact equality as well - I just wanted to demonstrate that for equality, equals also works.
And of course, there are the isAfter and isBefore methods that also do the comparison in an elegant way.
Is there a good way to get the date of the coming Wednesday?
That is, if today is Tuesday, I want to get the date of Wednesday in this week; if today is Wednesday, I want to get the date of next Wednesday; if today is Thursday, I want to get the date of Wednesday in the following week.
Thanks.
The basic algorithm is the following:
Get the current date
Get its day of week
Find its difference with Wednesday
If the difference is not positive, add 7 (i.e. insist on next coming/future date)
Add the difference
Here's a snippet to show how to do this with java.util.Calendar:
import java.util.Calendar;
public class NextWednesday {
public static Calendar nextDayOfWeek(int dow) {
Calendar date = Calendar.getInstance();
int diff = dow - date.get(Calendar.DAY_OF_WEEK);
if (diff <= 0) {
diff += 7;
}
date.add(Calendar.DAY_OF_MONTH, diff);
return date;
}
public static void main(String[] args) {
System.out.printf(
"%ta, %<tb %<te, %<tY",
nextDayOfWeek(Calendar.WEDNESDAY)
);
}
}
Relative to my here and now, the output of the above snippet is "Wed, Aug 18, 2010".
API links
java.util.Calendar
java.util.Formatter - for the formatting string syntax
tl;dr
LocalDate // Represent a date-only value, without time-of-day and without time zone.
.now() // Capture the current date as seen in the wall-clock time used by the people of a specific region (a time zone). The JVM’s current default time zone is used here. Better to specify explicitly your desired/expected time zone by passing a `ZoneId` argument. Returns a `LocalDate` object.
.with( // Generate a new `LocalDate` object based on values of the original but with some adjustment.
TemporalAdjusters // A class that provides some handy pre-defined implementations of `TemporalAdjuster` (note the singular) interface.
.next( // An implementation of `TemporalAdjuster` that jumps to another date on the specified day-of-week.
DayOfWeek.WEDNESDAY // Pass one of the seven predefined enum objects, Monday-Sunday.
) // Returns an object implementing `TemporalAdjuster` interface.
) // Returns a `LocalDate` object.
Details
Using Java8 Date time API you can easily find the coming Wednesday.
LocalDate nextWed = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY));
next(DayOfWeek dayOfWeek) - Returns the next day-of-week adjuster, which adjusts the date
to the first occurrence of the specified day-of-week after the date
being adjusted.
Suppose If you want to get previous Wednesday then,
LocalDate prevWed = LocalDate.now().with(TemporalAdjusters.previous(DayOfWeek.WEDNESDAY));
previous(DayOfWeek dayOfWeek) - Returns the previous day-of-week adjuster, which adjusts
the date to the first occurrence of the specified day-of-week before
the date being adjusted.
Suppose If you want to get next or current Wednesday then
LocalDate nextOrSameWed = LocalDate.now().with(TemporalAdjusters.nextOrSame(DayOfWeek.WEDNESDAY));
nextOrSame(DayOfWeek dayOfWeek) - Returns the next-or-same day-of-week
adjuster, which adjusts the date to the first occurrence of the
specified day-of-week after the date being adjusted unless it is
already on that day in which case the same object is returned.
Edit:
You can also pass ZoneId to get the current date from the system clock in the specified time-zone.
ZoneId zoneId = ZoneId.of("UTC");
LocalDate nextWed = LocalDate.now(zoneId).with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY));
For more information refer TemporalAdjusters
Using JodaTime:
LocalDate date = new LocalDate(System.currentTimeMillis());
Period period = Period.fieldDifference(date, date.withDayOfWeek(DateTimeConstants.WEDNESDAY));
int days = period.getDays();
if (days < 1) {
days = days + 7;
}
System.out.println(date.plusDays(days));
Calendar c= Calendar.getInstance();
c.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY);
c.add(Calendar.DAY_OF_MONTH, 7);
c.getTime();
Use java.util.Calendar. You get the current date/time like this:
Calendar date = Calendar.getInstance();
From there, get date.get(Calendar.DAY_OF_WEEK) to get the current day of week and get the difference to Calendar.WEDNESDAY and add it.
public static void nextWednesday() throws ParseException
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
int weekday = calendar.get(Calendar.DAY_OF_WEEK);
int days = Calendar.WEDNESDAY - weekday;
if (days < 0)
{
days += 7;
}
calendar.add(Calendar.DAY_OF_YEAR, days);
System.out.println(sdf.format(calendar.getTime()));
}