**I am trying to write the code for getting the date in required format , I have got the dates but how to add the required time with it ,
here I have
startDate - 1/08/2021 00:00:00 ,
EndDate - 20/08/2021 23:59:59 ,
increment days: 10
and the Expected output is :
05/08/2021 00:00:00 to 10/08/2021 23:59:59 , 11/08/2021 00:00:00 to 15/08/2021 23:59:59 ,
This is the Code which I was trying to write , any help is appreciated
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class DateTest {
public static List<LocalDate> getDaysBetweenDates(LocalDate startDate, LocalDate endDate, int interval) {
List<LocalDate> dates = new ArrayList<>();
while (endDate.isAfter(startDate)) {
dates.add(startDate);
startDate = startDate.plusDays(interval-1);
dates.add(startDate);
startDate = startDate.plusDays(1);
}
return dates;
}
public static void main(String[] args) {
int interval = 5;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss",Locale.US);
List<LocalDate> daysBetweenDates = getDaysBetweenDates(LocalDate.parse("01-08-2021 00:00:00", formatter),
LocalDate.parse("20-08-2021 23:59:59", formatter), interval);
System.out.println(daysBetweenDates);
}
}
Here's an alternative that uses LocalDates only (OK, and LocalDateTimes internally):
public static void printDaysInPeriod(LocalDate start, LocalDate end, int interval) {
// provide some data structure that
Map<LocalDate, LocalDate> intervals = new TreeMap<LocalDate, LocalDate>();
// loop through the dates in the defined period
while (start.isBefore(end)) {
// use the interval as step
LocalDate intervalEnd = start.plusDays(interval);
// store the sub-interval in the data structure
intervals.put(start, intervalEnd);
// and rearrange "start" to be the day after the last sub-interval
start = intervalEnd.plusDays(1);
}
// provide a formatter that produces the desired output per datetime
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"dd/MM/uuuu HH:mm:ss"
);
// provide a data structure for the output parts (Strings here)
List<String> intervalOutput = new ArrayList<>();
// stream the sub-intervals
intervals.entrySet().forEach(e ->
// then produce the desired output per sub-interval and store it
intervalOutput.add(e.getKey().atStartOfDay()
.format(formatter)
+ " to "
+ e.getValue()
.atTime(LocalTime.MAX)
.format(formatter)));
// finally output the sub-interval Strings comma-separated
System.out.println(String.join(" , ", intervalOutput));
}
Using this method in a main, like this
public static void main(String[] args) {
// example dates defining an interval
String startInterval = "05/08/2021";
String endInterval = "15/08/2021";
// provide a parser that handles the format
DateTimeFormatter dateParser = DateTimeFormatter.ofPattern("dd/MM/uuuu");
// then parse the dates to LocalDates
LocalDate start = LocalDate.parse(startInterval, dateParser);
LocalDate end = LocalDate.parse(endInterval, dateParser);
// and use the method
printDaysInPeriod(start, end, 5);
}
produces the following output:
05/08/2021 00:00:00 to 10/08/2021 23:59:59 , 11/08/2021 00:00:00 to 16/08/2021 23:59:59
You changed your questions a few times and in the first reading, I thought that you have start and end Date-Times as String. Based on this understanding, I wrote this answer. However, the very next minute, deHaar posted this correct answer. I am leaving this answer here for someone who will be looking for a solution to this kind of requirement (i.e. with Date-Time as String).
You can do it in the following two simple steps:
Define separate DateTimeFormatter for the input and the output strings
Loop through the parse range of Date-Time.
Demo
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strStartDateTime = "1/08/2021 00:00:00";
String strEndDateTime = "20/08/2021 23:59:59";
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("d/M/u H:m:s", Locale.ENGLISH);
LocalDateTime startDateTime = LocalDateTime.parse(strStartDateTime, dtfInput);
LocalDateTime endDateTime = LocalDateTime.parse(strEndDateTime, dtfInput);
DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH);
for (LocalDateTime ldt = startDateTime, nextDateTime = ldt.plusDays(10).minusSeconds(1); !ldt
.isAfter(endDateTime); ldt = ldt.plusDays(10), nextDateTime = ldt.plusDays(10).minusSeconds(1))
System.out.println(dtfOutput.format(ldt) + " - " + nextDateTime);
}
}
Output:
2021-08-01 00:00:00 - 2021-08-10T23:59:59
2021-08-11 00:00:00 - 2021-08-20T23:59:59
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.
Use the date-time API.
(The code should be self-explanatory.)
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class DateTest {
public static List<ZonedDateTime> getDaysBetweenDates(ZonedDateTime startDate, ZonedDateTime endDate, int interval) {
List<ZonedDateTime> dates = new ArrayList<>();
while (!startDate.isAfter(endDate)) {
dates.add(startDate);
if (Period.between(startDate.toLocalDate(), endDate.toLocalDate()).getDays() < interval) {
startDate = endDate;
}
else {
startDate = startDate.plusDays(interval);
}
dates.add(startDate);
startDate = startDate.plusDays(1);
}
return dates;
}
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss", Locale.ENGLISH);
List<ZonedDateTime> dates = getDaysBetweenDates(ZonedDateTime.of(LocalDateTime.parse("05/08/2021 00:00:00", formatter), ZoneId.systemDefault()),
ZonedDateTime.of(LocalDateTime.parse("15/08/2021 23:59:59", formatter), ZoneId.systemDefault()),
5);
for (int i = 0; i < dates.size(); i+=2) {
System.out.printf("%s to %s , ",
dates.get(i).format(formatter),
dates.get(i + 1).format(formatter));
}
}
}
Output when running above code as follows:
05/08/2021 00:00:00 to 10/08/2021 00:00:00 , 11/08/2021 00:00:00 to 15/08/2021 23:59:59 ,
Related
I get a timestamp in the format "20210908094049.884Z". This is the last modify timestamp from an LDAP object. I use Spring Boot Ldap. I have no clue how to parse this String in a Datetime like dd.MM.yyyy HH:mm.
Can anyone help me please?
Here is an example:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
public static void main(String[] args) {
// Creating new simple date formatter with the format you've given
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
// Defining the input date
String inputDate = "20210908094049.884Z";
// Parsing the date, catching the parse exception if date is malformatted
Date date = null;
try {
// Date ends on a Z, we remove this Z (Z is for timezone UTC +0:00)
date = format.parse(inputDate.replace("Z", ""));
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
Giving following output:
Wed Sep 08 09:40:49 CEST 2021
Edit:
Here another even better solution from Ole V.V.
import java.time.Instant;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
Instant instant = DateTimeFormatter
// Defining pattern to parse
.ofPattern("yyyyMMddHHmmss.SSSXX")
// Defining input to parse with pattern
.parse("20210908094049.884Z", Instant::from);
System.out.println(instant);
}
}
Output is an instant with value:
2021-09-08T09:40:49.884Z
java.time
I recommend that you use java.time, the modern Java date and time API, for your work with timestamps.
The LDAP timestamp format has a number of allowed variations (see the link at the bottom). The following formatter takes many of them into account, not all of them.
private static final DateTimeFormatter LDAP_PARSER = new DateTimeFormatterBuilder()
.appendPattern("uuuuMMddHHmmss")
.optionalStart()
.appendPattern("[.][,]")
.appendFraction(ChronoField.NANO_OF_SECOND, 1, 9, false)
.optionalEnd()
.appendPattern("[XX][X]")
.toFormatter(Locale.ROOT);
With this formatter we may for example parse your string into an OffsetDateTime:
String ldapTimestampString = "20210908094049.884Z";
OffsetDateTime timestamp = OffsetDateTime.parse(ldapTimestampString, LDAP_PARSER);
System.out.println(timestamp);
Output is:
2021-09-08T09:40:49.884Z
Formatting
To convert the timestamp to a string containing date and time you need to decide on a time zone for that since it is never the same date nor the same time in all time zones.
Use this formatter:
private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
Then do:
ZoneId zone = ZoneId.of("Pacific/Tarawa");
ZonedDateTime dateTime = timestamp.atZoneSameInstant(zone);
String formattedDateTime = dateTime.format(FORMATTER);
System.out.println(formattedDateTime);
08.09.2021 21:40
Links
Oracle tutorial: Date Time explaining how to use java.time.
GeneralizedTime on ldapwiki defining the LDAP timestamp format.
I had help setting up a function to take two strings and merge them into a date object.
Java - Take two strings and combine into a single date object
This has been working fine until it tries to parse 1st June, then i get the below error
Exception in thread "AWT-EventQueue-0" java.time.format.DateTimeParseException: Text '1st June' could not be parsed, unparsed text found at index 7
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1952)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
at java.time.LocalDate.parse(LocalDate.java:400)
at Timetable.ClassManager.parseDate(ClassManager.java:201)
at Timetable.GoogleAPI.loadClasses(GoogleAPI.java:133)
at Timetable.ClassManager.loadClasses(ClassManager.java:58)
The code for the function is
public LocalDateTime parseDate(String strDate, String strTime) {
strTime = strTime + ":00";
System.out.println("Date: " + strDate);
System.out.println("Time: " + strTime);
LocalDate date = LocalDate.now();
DateTimeFormatter dtfForDate = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.parseDefaulting(ChronoField.YEAR, date.getYear())
.appendPattern("d['th']['st']['rd']['nd'] MMM")
.toFormatter(Locale.ENGLISH);
DateTimeFormatter dtfForTime = DateTimeFormatter.ofPattern("H:m:s", Locale.ENGLISH);
LocalDateTime ldt = LocalDate.parse(strDate, dtfForDate)
.atTime(LocalTime.parse(strTime, dtfForTime));
System.out.println("Local Date Time: " + ldt);
return ldt;
}
The two prints give me
Date: 1st June
Time: 9:15:00
I would need to be able to handle both full month names and month abbreviations, i.e., March was set as Mar, April as Apr.
Use the following pattern which will cater to both, the three-letter abbreviated month names as well as the full month names:
.appendPattern("d['th']['st']['rd']['nd'] [MMMM][MMM]")
Demo:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
System.out.println(parseDate("1st June", "9:15:00"));
System.out.println(parseDate("1st Jun", "9:15:00"));
}
public static LocalDateTime parseDate(String strDate, String strTime) {
LocalDate date = LocalDate.now();
DateTimeFormatter dtfForDate = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.parseDefaulting(ChronoField.YEAR, date.getYear())
.appendPattern("d['th']['st']['rd']['nd'] [MMMM][MMM]")
.toFormatter(Locale.ENGLISH);
DateTimeFormatter dtfForTime = DateTimeFormatter.ofPattern("H:m:s", Locale.ENGLISH);
LocalDateTime ldt = LocalDate.parse(strDate, dtfForDate).atTime(LocalTime.parse(strTime, dtfForTime));
return ldt;
}
}
Output:
2021-06-01T09:15
2021-06-01T09:15
Update
This update addresses the following concern raised by Meno Hochschild:
Personally, I don't like the misuse of optional sections here.
Negative example: "1th Jun" or "2st Jun" would also be successfully
parsed but should not.
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class Main {
public static void main(String[] args) {
System.out.println(parseDate("1st June", "9:15:00"));
System.out.println(parseDate("1st Jun", "9:15:00"));
}
public static LocalDateTime parseDate(String strDate, String strTime) {
LocalDate date = LocalDate.now();
DateTimeFormatter dtfForDate = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.parseDefaulting(ChronoField.YEAR, date.getYear())
.appendText(ChronoField.DAY_OF_MONTH, ordinalMap())
.appendPattern(" [MMMM][MMM]")
.toFormatter(Locale.ENGLISH);
DateTimeFormatter dtfForTime = DateTimeFormatter.ofPattern("H:m:s", Locale.ENGLISH);
LocalDateTime ldt = LocalDate.parse(strDate, dtfForDate).atTime(LocalTime.parse(strTime, dtfForTime));
return ldt;
}
static Map<Long, String> ordinalMap() {
String[] suffix = { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
Map<Long, String> map = new HashMap<>();
for (int i = 1; i <= 31; i++)
map.put((long)i, String.valueOf(i) + suffix[(i > 3 && i < 21) ? 0 : (i % 10)]);
return map;
}
}
Output:
2021-06-01T09:15
2021-06-01T09:15
Courtesy: The logic to build the Map is based on this excellent answer.
Given:
public static void main(String[] args) {
String dateString = "2018-07-30T13:36:17.820";
DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
LocalDate date = LocalDate.parse(dateString, DATE_TIME_FORMATTER);
ZonedDateTime zonedDateTime = date.atStartOfDay((ZoneOffset.UTC));
System.out.println(zonedDateTime);
}
And output:
2018-07-30T00:00Z
...what is the pattern to print seconds? Stupid question no doubt but driving me a little nuts
I need:
2018-07-30T00:00:00Z
I changed java.time.LocalDate to java.time.LocalDateTime, you need it if you want to show also the seconds.
package com.test;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class DateFormatter {
public static void main(String[] args) {
String dateString = "2018-07-30T13:36:17.820";
DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
LocalDateTime date = LocalDateTime.parse(dateString, DATE_TIME_FORMATTER);
ZonedDateTime zonedDateTime = date.atZone(ZoneOffset.UTC);
System.out.println(zonedDateTime);
}
}
Output is:
2018-07-30T13:36:17.820Z
LocalDate will keep just date. You need to parse LocalDateTime and convert to ZonedDateTime and you will have seconds as you expect.
var dateString = "2018-07-30T13:36:17.820";
var format = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
var localDate = LocalDateTime.parse(dateString, format);
var zone = ZoneId.of( "America/Montreal" );
var zonedDateTime = localDate.atZone(zone);
System.out.println(zonedDateTime);
You will have to go a few steps:
parse the String to a LocalDateTime because it contains date and time of day
extract the date only
create a ZonedDateTime out of that by adding the start of day (LocalTime.MIN = 00:00:00) and a ZoneOffset.UTC
This code may do:
public static void main(String[] args) {
String dateString = "2018-07-30T13:36:17.820";
// parse a LocalDateTime
LocalDateTime localDateTime = LocalDateTime.parse(dateString);
// extract the date part
LocalDate localDate = localDateTime.toLocalDate();
// make it a ZonedDateTime by applying a ZoneId
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDate, LocalTime.MIN, ZoneOffset.UTC);
// print the result
System.out.println(zonedDateTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
}
Output is
2018-07-30T00:00:00Z
There are several ways to do it, this is just one of them and it just slightly differs from most of the other answers (and comments :-) ).
tl;dr
You have used the wrong things in the wrong places.
You do not need a DateTimeFormatter explicitly in order to parse 2018-07-30T13:36:17.820 because it's already in ISO 8601 format which is also the default format used by LocalDateTime#parse. Moreover, this string has date and time instead of just date; therefore, it makes more sense to parse it into LocalDateTime instead of LocalDate. You can always get LocalDate from LocalDateTime using LocalDateTime#toLocalDate.
The ZonedDateTime#toString uses the LocalDateTime#toString which in turn uses LocalTime#toString for the time part which omits second and fraction-of-second if they are zero. If you need a string with zero second and fraction-of-second, you will need to use a DateTimeFormatter.
Demo:
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String args[]) {
String dateString = "2018-07-30T13:36:17.820";
LocalDateTime localDateTime = LocalDateTime.parse(dateString);// You do not need a DateTimeFormatter here
ZonedDateTime zonedDateTime = localDateTime.toLocalDate().atStartOfDay(ZoneOffset.UTC);
// Print zonedDateTime.toString()
System.out.println(zonedDateTime);
// Custom format
final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
System.out.println(DATE_TIME_FORMATTER.format(zonedDateTime));
}
}
Output:
2018-07-30T00:00Z
2018-07-30T00:00:00.000
Learn more about the modern date-time API from Trail: Date Time.
I need to get the next datetime when it's say, 20.00 o'clock.
So for instance, if it's 13.00 hours, it'd give me the datetime corresponding to today at 20.00.
But if it's 21.00, it'd give me tomorrow at 20.00.
How can I achieve this? Is there some built in function that I just can't find the name of?
In a pinch I could also use Java Time instead of Joda Time.
Add one day to DateTime if the time is past 20:00.
Demo:
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalTime;
public final class Main {
public static final void main(String[] args) {
// Test
System.out.println(getNextTime("13.00"));
System.out.println(getNextTime("21.00"));
}
static DateTime getNextTime(String strTime) {
LocalTime time = LocalTime.parse(strTime);
DateTime dt = DateTime.now(DateTimeZone.getDefault()).withTime(new LocalTime(20, 0));
if (time.isAfter(new LocalTime(20, 0))) {
dt = dt.plusDays(1);
}
return dt;
}
}
Output:
2021-03-29T20:00:00.000+01:00
2021-03-30T20:00:00.000+01:00
Note: Check the following notice at the Home Page of Joda-Time
Joda-Time is the de facto standard date and time library for Java
prior to Java SE 8. Users are now asked to migrate to java.time
(JSR-310).
Using the modern date-time API:
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public final class Main {
public static final void main(String[] args) {
// Test
System.out.println(getNextTime("13.00"));
System.out.println(getNextTime("21.00"));
}
static ZonedDateTime getNextTime(String strTime) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("HH.mm");
LocalTime time = LocalTime.parse(strTime, dtf);
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.systemDefault()).withHour(20);
if (time.isAfter(LocalTime.of(20, 0))) {
zdt = zdt.plusDays(1);
}
return zdt;
}
}
Output:
2021-03-29T20:00:18.325419+01:00[Europe/London]
2021-03-30T20:00:18.327587+01:00[Europe/London]
I am trying to get a list of string dates in Scala for a given range. Is there a direct/shorter way to achieve this?
val format = "yyyMMdd"
val startDate = "20200101"
val endDate = "20200131"
Expected Output = List(2020101,20200102, ....., 20200131)
Ya...if you add dashes in the format you gave you can use LocalData to parse the date without using a date formatter to complicate it. e.g. yyyy-MM-dd
val startDate = LocalDate.parse("2020-01-01")
val endDate = LocalDate.parse("2020-01-31")
Then you can use java.time.LocalDate.datesUntil to generate the dates for you. After that there is some collection manipulation to do if you really want a List and some String manipulation to do for a date without dashes. This gets you most of the way.
startDate.datesUntil(endDate).collect(Collectors.toList()).asScala.map(date => date.toString)
List[String] = ArrayBuffer(2020-01-01, 2020-01-02, 2020-01-03, ...).toList
You can do it as follows:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
// Tests
System.out.println(getDateList("20200101", "20200110"));
System.out.println(getDateList("20200101", "20200131"));
}
static List<String> getDateList(String strStartDate, String strEndDate) {
// List to be populated with the desired strings
List<String> result = new ArrayList<>();
// Formatter for the desired pattern
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
// Parse strings to LocalDate instances
LocalDate startDate = LocalDate.parse(strStartDate, formatter);
LocalDate endDate = LocalDate.parse(strEndDate, formatter);
// Loop starting with start date until end date with a step of one day
for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
result.add(date.format(formatter));
}
// Return the populated list
return result;
}
}
Output:
[20200101, 20200102, 20200103,..., 20200110]
[20200101, 20200102, 20200103,..., 20200131]
Solution using Java Stream API:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Tests
System.out.println(getDateList("20200101", "20200110"));
System.out.println(getDateList("20200101", "20200131"));
}
static List<String> getDateList(String strStartDate, String strEndDate) {
// Formatter for the input and desired pattern
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
// Parse strings to LocalDate instances
LocalDate startDate = LocalDate.parse(strStartDate, formatter);
LocalDate endDate = LocalDate.parse(strEndDate, formatter);
return Stream.iterate(startDate, date -> date.plusDays(1))
.limit(ChronoUnit.DAYS.between(startDate, endDate.plusDays(1)))
.map(date -> date.format(formatter))
.collect(Collectors.toList());
}
}