Calculating time between datetimes - java

Let's say I have two datetimes, 30-11-2015 10:00 and 02-12-2015 15:00. I also have two times, 07:00 and 22:00. How could I calculate the amount of time passed between the two date/times that was within the second times? Using Calendar object? It seems simple but its boggling my mind.

Since none of the other answers include runnable code, I can't tell if they solve the problem or not.
To calculate the duration of a time range within a date range, you have to:
Split the date range into multiple date ranges, each spanning no more than one day.
Calculate the time range within each day date range
Taking the example date range from the question. 30-11-2015 10:00 and 02-12-2015 15:00, we generate the following split day date ranges:
30-11-2015 10:00 - 30-11-2015 24:00
01-12-2015 00:00 - 01-12-2015 24:00
02-12-2015 00:00 - 02-12-2015 15:00
Now, we can apply the time range of 7:00 - 22:00 to each of the split day date ranges.
30-11-2015 10:00 - 30-11-2015 24:00 -> 12 hours
01-12-2015 00:00 - 01-12-2015 24:00 -> 15 hours
02-12-2015 00:00 - 02-12-2015 15:00 -> 8 hours
For a total of 35 hours. The actual calculation would probably be in minutes instead of hours.
Edited to add: I created a Time and a TimeRange class to hold the time and a day time range, respectively. I used the java.util.Date, although I had to create my own increment a day method.
I put all of the classes together so I could post this easier. The classes should be put in separate files.
package com.ggl.testing;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class TimeRangeTest {
private static final SimpleDateFormat inputDateFormat = new SimpleDateFormat(
"dd-MM-yyyy");
public static void main(String[] args) {
TimeRangeTest test = new TimeRangeTest();
int minutes = test.calculateTotalMinutes("30-11-2015 10:00",
"02-12-2015 15:00", "07:00", "22:00");
System.out.println(minutes + " minutes, " + (minutes / 60) + " hours");
}
public int calculateTotalMinutes(String startDateTimeString,
String endDateTimeString, String startTimeString,
String endTimeString) {
try {
List<TimeRange> timeRanges = generateTimeRanges(
startDateTimeString, endDateTimeString);
return calculateTimeRange(timeRanges, startTimeString,
endTimeString);
} catch (ParseException e) {
e.printStackTrace();
return 0;
}
}
private List<TimeRange> generateTimeRanges(String startDateTimeString,
String endDateTimeString) throws ParseException {
Date startDate = inputDateFormat.parse(startDateTimeString.substring(0,
10));
Time startTime = new Time(startDateTimeString.substring(11));
Date endDate = inputDateFormat
.parse(endDateTimeString.substring(0, 10));
Time endTime = new Time(endDateTimeString.substring(11));
List<TimeRange> timeRanges = new ArrayList<>();
Date currentDate = new Date(startDate.getTime());
Time currentTime = new Time(startTime);
Time eodTime = new Time("24:00");
while (currentDate.compareTo(endDate) < 0) {
TimeRange timeRange = new TimeRange(currentDate, currentTime,
eodTime);
timeRanges.add(timeRange);
currentTime = new Time("00:00");
currentDate = new Date(currentDate.getTime() + 24L * 60L * 60L
* 1000L);
}
TimeRange timeRange = new TimeRange(currentDate, currentTime, endTime);
timeRanges.add(timeRange);
return timeRanges;
}
private int calculateTimeRange(List<TimeRange> timeRanges,
String startTimeString, String endTimeString) {
int count = 0;
Time startTime = new Time(startTimeString);
Time endTime = new Time(endTimeString);
for (TimeRange timeRange : timeRanges) {
Time sodTime = new Time(timeRange.getStartTime());
Time eodTime = new Time(timeRange.getEndTime());
Time sTime = startTime.max(sodTime);
Time eTime = endTime.min(eodTime);
count += eTime.difference(sTime);
}
return count;
}
public class TimeRange {
private final SimpleDateFormat inputDateFormat = new SimpleDateFormat(
"dd-MM-yyyy");
private final Date date;
private final Time startTime;
private final Time endTime;
public TimeRange(Date date, Time startTime, Time endTime) {
this.date = date;
this.startTime = startTime;
this.endTime = endTime;
}
public Date getDate() {
return date;
}
public Time getStartTime() {
return startTime;
}
public Time getEndTime() {
return endTime;
}
#Override
public String toString() {
return inputDateFormat.format(getDate()) + " "
+ startTime.toString() + " -> " + endTime.toString();
}
}
public class Time {
private final int minutesPastMidnight;
public Time(String timeString) {
int hours = Integer.valueOf(timeString.substring(0, 2));
int minutes = Integer.valueOf(timeString.substring(3, 5));
this.minutesPastMidnight = hours * 60 + minutes;
}
public Time(Time time) {
this.minutesPastMidnight = time.getMinutesPastMidnight();
}
private int getMinutesPastMidnight() {
return minutesPastMidnight;
}
public int difference(Time time) {
return this.getMinutesPastMidnight()
- time.getMinutesPastMidnight();
}
public Time min(Time time) {
return (difference(time) > 0) ? time : this;
}
public Time max(Time time) {
return (difference(time) > 0) ? this : time;
}
#Override
public String toString() {
int hours = minutesPastMidnight / 60;
int minutes = minutesPastMidnight - (hours * 60);
return String.format("%02d:%02d", hours, minutes);
}
}
}

If you use java8, you can use LocalDateTime. Then your code could looks like this:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTimeStart = LocalDateTime.parse("2015-10-01 10:00", formatter);
LocalDateTime dateTimeEnd = LocalDateTime.parse("2015-10-02 10:00", formatter);
long seconds = Duration.between(dateTimeStart, dateTimeEnd).getSeconds();
Or LocalTime if you have only time. Then it could looks like this:
LocalTime timeStart = LocalTime.parse("07:00");
LocalTime timeEnd = LocalTime.parse("22:00");
long seconds = Duration.between(timeStart, timeEnd).getSeconds();
If you can't use java8, you can get the number of milliseconds since 1970-01-01 00:00:00 to your date using getTime() method and do simple subtraction operation, like this:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
Date dateStart = simpleDateFormat.parse("2015-10-01 10:00");
Date dateEnd = simpleDateFormat.parse("2015-10-02 10:00");
long milliseconds = dateEnd.getTime() - dateStart.getTime();
long seconds = resultInMillisecond / 1000;

Related

what is the best solution to split in chunk monthly given two dates startTime and EndTime in Java?

I have to create algorithm to compute the chunk monthly given two dates.
example (format date: yyyy-MM-dd hh:mm:ss) given two dates:
startTime: : 2020-01-10 13:00:25
endTime : 2020-03-19 15:00:30
I have to divide in chunk monthly the period above.
In a nutshell if I compute the chunks would be :
chunk_1 --> from: 2020-01-10 13:00:25 to: 2020-01-31 23:59:59
chunk_2 --> from: 2020-02-01 00:00:00 to: 2020-02-29 23:59:59
chunk_3 --> from: 2020-03-01 00:00:00 to: 2020-03-19 15:00:30
my first solution is the followed:
public static List<ExportDateSegment> datesBetweenWithCalendar(Date d1, Date d2) {
List<ExportDateSegment> dateSegments = new ArrayList<ExportDateSegment>();
Calendar c1 = Calendar.getInstance();
c1.setTime(d1);
int monthsDiff = mounthsDiffbetween(d1, d2);
LOGGER.debug("months between two dates: {} ",monthsDiff);
int i = 1;
while (c1.getTimeInMillis() < d2.getTime()) {
Calendar calendar;
ExportDateSegment exportDateSegment = new ExportDateSegment();
LOGGER.debug("last day of the month: " + c1.getActualMaximum(Calendar.DATE) + " last hour of the month: "
+ c1.getActualMaximum(Calendar.HOUR_OF_DAY) + " first day of the month: "
+ c1.getActualMinimum(Calendar.DAY_OF_MONTH) + " month: " + (c1.get(Calendar.MONTH) + 1));
// the logic is to separate the three cases: the start period, intermediate period and the end period
if (i == 1) {
calendar = new GregorianCalendar(c1.get(Calendar.YEAR), c1.get(Calendar.MONTH),
c1.getActualMaximum(Calendar.DATE), 23, 59, 59);
exportDateSegment.setStartDate(c1.getTime());
exportDateSegment.setEndDate(calendar.getTime());
} else if (i == monthsDiff) {
calendar = new GregorianCalendar(c1.get(Calendar.YEAR), c1.get(Calendar.MONTH),
c1.getActualMinimum(Calendar.DATE), 00, 00, 00);
exportDateSegment.setStartDate(calendar.getTime());
exportDateSegment.setEndDate(d2);
} else {
Calendar startCalendar = new GregorianCalendar(c1.get(Calendar.YEAR), c1.get(Calendar.MONTH),
c1.getActualMinimum(Calendar.DATE), 00, 00, 00);
Calendar endCalendar = new GregorianCalendar(c1.get(Calendar.YEAR), c1.get(Calendar.MONTH),
c1.getActualMaximum(Calendar.DATE), 23, 59, 59);
exportDateSegment.setStartDate(startCalendar.getTime());
exportDateSegment.setEndDate(endCalendar.getTime());
}
c1.add(Calendar.MONTH, 1);
dateSegments.add(exportDateSegment);
i = i + 1;
}
return dateSegments;
}
public static int mounthsDiffbetween(Date d1, Date d2) {
int monthsDiff = 0;
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.setTime(d1);
c2.setTime(d2);
monthsDiff = (c2.get(Calendar.MONTH) - c1.get(Calendar.MONTH)) + 1;
return monthsDiff;
}
ExportDateSegment is the bean that contains
startDate and endDate as attributes, in other words are the chunk.
Is there a smarter solution ?
You should use the Java 8 Time API, e.g. like this:
static List<TemporalRange<LocalDateTime>> chunkMonthly(LocalDateTime start, LocalDateTime end) {
List<TemporalRange<LocalDateTime>> list = new ArrayList<>();
for (LocalDateTime chunkEnd = end, chunkStart; ! chunkEnd.isBefore(start); chunkEnd = chunkStart.minusSeconds(1)) {
chunkStart = chunkEnd.toLocalDate().withDayOfMonth(1).atStartOfDay();
if (chunkStart.isBefore(start))
chunkStart = start;
list.add(new TemporalRange<>(chunkStart, chunkEnd));
}
Collections.reverse(list);
return list;
}
class TemporalRange<T extends TemporalAccessor> {
private final T start;
private final T end;
public TemporalRange(T start, T end) {
this.start = start;
this.end = end;
}
public T getStart() {
return this.start;
}
public T getEnd() {
return this.end;
}
#Override
public String toString() {
return this.start + " to " + this.end;
}
public String toString(DateTimeFormatter fmt) {
return fmt.format(this.start) + " to " + fmt.format(this.end);
}
}
Test
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
List<TemporalRange<LocalDateTime>> list = chunkMonthly(
LocalDateTime.parse("2020-01-10 13:00:25", fmt),
LocalDateTime.parse("2020-03-19 15:00:30", fmt));
list.forEach(r -> System.out.println(r.toString(fmt)));
Output
2020-01-10 13:00:25 to 2020-01-31 23:59:59
2020-02-01 00:00:00 to 2020-02-29 23:59:59
2020-03-01 00:00:00 to 2020-03-19 15:00:30
You should definitely use the java.time classes to do this. There are built in TemporalAdjusters that help you find the first and last day of a month.
public static List<ExportDateSegment> splitIntoMonths(LocalDateTime start, LocalDateTime end) {
LocalDate segmentEndDate =
start.with(TemporalAdjusters.lastDayOfMonth()).toLocalDate();
LocalTime segmentEndTime = LocalTime.of(23, 59, 59);
LocalDate lastSegmentStartDate = end.with(TemporalAdjusters.firstDayOfMonth()).toLocalDate();
LocalTime segmentStartTime = LocalTime.of(0, 0, 0);
if (lastSegmentStartDate.isBefore(segmentEndDate)) { // start & end are in the same month
return Collections.singletonList(new ExportDateSegment(start, end));
}
ArrayList<ExportDateSegment> list = new ArrayList<>();
// adds the first segment, which is not a whole month
list.add(new ExportDateSegment(start, LocalDateTime.of(segmentEndDate, segmentEndTime)));
// just like a typical for loop, but with LocalDate
for (LocalDate segmentStartDate = segmentEndDate.plusDays(1) ; segmentStartDate.isBefore(lastSegmentStartDate) ; segmentStartDate = segmentStartDate.plusMonths(1)) {
list.add(new ExportDateSegment(
LocalDateTime.of(segmentStartDate, segmentStartTime),
LocalDateTime.of(segmentStartDate.with(TemporalAdjusters.lastDayOfMonth()), segmentEndTime)
));
}
// adds the last segment, which is also not a whole month
list.add(new ExportDateSegment(LocalDateTime.of(lastSegmentStartDate, segmentStartTime), end));
return list;
}
Here is another one using streams:
public class SplitDateRange {
public static class Range {
private final LocalDateTime start;
private final LocalDateTime end;
public Range(LocalDateTime start, LocalDateTime end) {
this.start = start;
this.end = end;
}
#Override
public String toString() {
return "Range{" + "start=" + start + ", end=" + end + '}';
}
}
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.parse("2020-01-10T13:00:25", DateTimeFormatter.ISO_LOCAL_DATE_TIME);
LocalDateTime end = LocalDateTime.parse("2020-03-19T15:00:30", DateTimeFormatter.ISO_LOCAL_DATE_TIME);
Stream.iterate(start, date -> date.isBefore(end), SplitDateRange::firstDateTimeOfNextMonth)
.map(date -> new Range(date, min(end, firstDateTimeOfNextMonth(date).minusSeconds(1))))
.collect(Collectors.toList())
.forEach(System.out::println);
}
public static LocalDateTime firstDateTimeOfNextMonth(LocalDateTime current) {
return current.plusMonths(1).with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
}
public static LocalDateTime min(LocalDateTime a, LocalDateTime b) {
return a.isBefore(b) ? a : b;
}
}

Implement Java method for test data [duplicate]

I'm trying to generate a random date of birth for people in my database using a Java program. How would I do this?
import java.util.GregorianCalendar;
public class RandomDateOfBirth {
public static void main(String[] args) {
GregorianCalendar gc = new GregorianCalendar();
int year = randBetween(1900, 2010);
gc.set(gc.YEAR, year);
int dayOfYear = randBetween(1, gc.getActualMaximum(gc.DAY_OF_YEAR));
gc.set(gc.DAY_OF_YEAR, dayOfYear);
System.out.println(gc.get(gc.YEAR) + "-" + (gc.get(gc.MONTH) + 1) + "-" + gc.get(gc.DAY_OF_MONTH));
}
public static int randBetween(int start, int end) {
return start + (int)Math.round(Math.random() * (end - start));
}
}
java.util.Date has a constructor that accepts milliseconds since The Epoch, and java.util.Random has a method that can give you a random number of milliseconds. You'll want to set a range for the random value depending on the range of DOBs that you want, but those should do it.
Very roughly:
Random rnd;
Date dt;
long ms;
// Get a new random instance, seeded from the clock
rnd = new Random();
// Get an Epoch value roughly between 1940 and 2010
// -946771200000L = January 1, 1940
// Add up to 70 years to it (using modulus on the next long)
ms = -946771200000L + (Math.abs(rnd.nextLong()) % (70L * 365 * 24 * 60 * 60 * 1000));
// Construct a date
dt = new Date(ms);
Snippet for a Java 8 based solution:
Random random = new Random();
int minDay = (int) LocalDate.of(1900, 1, 1).toEpochDay();
int maxDay = (int) LocalDate.of(2015, 1, 1).toEpochDay();
long randomDay = minDay + random.nextInt(maxDay - minDay);
LocalDate randomBirthDate = LocalDate.ofEpochDay(randomDay);
System.out.println(randomBirthDate);
Note: This generates a random date between 1Jan1900 (inclusive) and 1Jan2015 (exclusive).
Note: It is based on epoch days, i.e. days relative to 1Jan1970 (EPOCH) - positive meaning after EPOCH, negative meaning before EPOCH
You can also create a small utility class:
public class RandomDate {
private final LocalDate minDate;
private final LocalDate maxDate;
private final Random random;
public RandomDate(LocalDate minDate, LocalDate maxDate) {
this.minDate = minDate;
this.maxDate = maxDate;
this.random = new Random();
}
public LocalDate nextDate() {
int minDay = (int) minDate.toEpochDay();
int maxDay = (int) maxDate.toEpochDay();
long randomDay = minDay + random.nextInt(maxDay - minDay);
return LocalDate.ofEpochDay(randomDay);
}
#Override
public String toString() {
return "RandomDate{" +
"maxDate=" + maxDate +
", minDate=" + minDate +
'}';
}
}
and use it like this:
RandomDate rd = new RandomDate(LocalDate.of(1900, 1, 1), LocalDate.of(2010, 1, 1));
System.out.println(rd.nextDate());
System.out.println(rd.nextDate()); // birthdays ad infinitum
You need to define a random date, right?
A simple way of doing that is to generate a new Date object, using a long (time in milliseconds since 1st January, 1970) and substract a random long:
new Date(Math.abs(System.currentTimeMillis() - RandomUtils.nextLong()));
(RandomUtils is taken from Apache Commons Lang).
Of course, this is far to be a real random date (for example you will not get date before 1970), but I think it will be enough for your needs.
Otherwise, you can create your own date by using Calendar class:
int year = // generate a year between 1900 and 2010;
int dayOfYear = // generate a number between 1 and 365 (or 366 if you need to handle leap year);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, randomYear);
calendar.set(Calendar.DAY_OF_YEAR, dayOfYear);
Date randomDoB = calendar.getTime();
For Java8 -> Assumming the data of birth must be before current day:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.temporal.ChronoUnit;
import java.util.Random;
public class RandomDate {
public static LocalDate randomBirthday() {
return LocalDate.now().minus(Period.ofDays((new Random().nextInt(365 * 70))));
}
public static void main(String[] args) {
System.out.println("randomDate: " + randomBirthday());
}
}
If you don't mind adding a new library to your code you can use MockNeat (disclaimer: I am one of the authors).
MockNeat mock = MockNeat.threadLocal();
// Generates a random date between [1970-1-1, NOW)
LocalDate localDate = mock.localDates().val();
System.out.println(localDate);
// Generates a random date in the past
// but beore 1987-1-30
LocalDate min = LocalDate.of(1987, 1, 30);
LocalDate past = mock.localDates().past(min).val();
System.out.println(past);
LocalDate max = LocalDate.of(2020, 1, 1);
LocalDate future = mock.localDates().future(max).val();
System.out.println(future);
// Generates a random date between 1989-1-1 and 1993-1-1
LocalDate start = LocalDate.of(1989, 1, 1);
LocalDate stop = LocalDate.of(1993, 1, 1);
LocalDate between = mock.localDates().between(start, stop).val();
System.out.println(between);
Generating random Date of Births:
import java.util.Calendar;
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(randomDOB());
}
}
public static String randomDOB() {
int yyyy = random(1900, 2013);
int mm = random(1, 12);
int dd = 0; // will set it later depending on year and month
switch(mm) {
case 2:
if (isLeapYear(yyyy)) {
dd = random(1, 29);
} else {
dd = random(1, 28);
}
break;
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
dd = random(1, 31);
break;
default:
dd = random(1, 30);
break;
}
String year = Integer.toString(yyyy);
String month = Integer.toString(mm);
String day = Integer.toString(dd);
if (mm < 10) {
month = "0" + mm;
}
if (dd < 10) {
day = "0" + dd;
}
return day + '/' + month + '/' + year;
}
public static int random(int lowerBound, int upperBound) {
return (lowerBound + (int) Math.round(Math.random()
* (upperBound - lowerBound)));
}
public static boolean isLeapYear(int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
int noOfDays = calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
if (noOfDays > 365) {
return true;
}
return false;
}
}
You can checkout randomizer for random data generation.This library helps to create random data from given Model class.Checkout below example code.
public class Person {
#DateValue( from = "01 Jan 1990",to = "31 Dec 2002" , customFormat = "dd MMM yyyy")
String dateOfBirth;
}
//Generate random 100 Person(Model Class) object
Generator<Person> generator = new Generator<>(Person.class);
List<Person> persons = generator.generate(100);
As there are many built in data generator is accessible using annotation,You also can build custom data generator.I suggest you to go through documentation provided on library page.
Look this method:
public static Date dateRandom(int initialYear, int lastYear) {
if (initialYear > lastYear) {
int year = lastYear;
lastYear = initialYear;
initialYear = year;
}
Calendar cInitialYear = Calendar.getInstance();
cInitialYear.set(Calendar.YEAR, 2015);
long offset = cInitialYear.getTimeInMillis();
Calendar cLastYear = Calendar.getInstance();
cLastYear.set(Calendar.YEAR, 2016);
long end = cLastYear.getTimeInMillis();
long diff = end - offset + 1;
Timestamp timestamp = new Timestamp(offset + (long) (Math.random() * diff));
return new Date(timestamp.getTime());
}
I think this will do the trick:
public static void main(String[] args) {
Date now = new Date();
long sixMonthsAgo = (now.getTime() - 15552000000l);
long today = now.getTime();
for(int i=0; i<10; i++) {
long ms = ThreadLocalRandom.current().nextLong(sixMonthsAgo, today);
Date date = new Date(ms);
System.out.println(date.toString());
}
}
If you don't mind a 3rd party library, the Utils library has a RandomDateUtils that generates random java.util.Dates and all the dates, times, instants, and durations from Java 8's date and time API
LocalDate birthDate = RandomDateUtils.randomPastLocalDate();
LocalDate today = LocalDate.now();
LocalDate under18YearsOld = RandomDateUtils.randomLocalDate(today.minus(18, YEARS), today);
LocalDate over18YearsOld = RandomDateUtils.randomLocalDateBefore(today.minus(18, YEARS));
It is in the Maven Central Repository at:
<dependency>
<groupId>com.github.rkumsher</groupId>
<artifactId>utils</artifactId>
<version>1.3</version>
</dependency>
simplest method:
public static LocalDate randomDateOfBirth() {
final int maxAge = 100 * 12 * 31;
return LocalDate.now().minusDays(new Random().nextInt(maxAge));
}
Using the original answer and adapting it to the new java.time.* api and adding ways to generate n random dates -- the function will return a List.
// RandomBirthday.java
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class RandomBirthday {
public static List<String> getRandomBirthday(int groupSize, int minYear, int maxYear) {
/** Given a group size, this method will return `n` random birthday
* between 1922-2022 where `n=groupSize`.
*
* #param groupSize the number of random birthday to return
* #param minYear the min year [lower bound]
* #param maxYear the max year [upper bound]
* #return a list of random birthday with format YYYY-MM-DD
*/
ArrayList<String> birthdays = new ArrayList<>();
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");
for (int i = 0; i < groupSize; i++) {
LocalDate baseDate = LocalDate.now();
LocalDate baseYear = baseDate.withYear(ThreadLocalRandom.current().nextInt(minYear, maxYear));
int dayOfYear = ThreadLocalRandom.current().nextInt(1, baseYear.lengthOfYear());
LocalDate baseRandBirthday = baseYear.withDayOfYear(dayOfYear);
LocalDate randDate = LocalDate.of(
baseRandBirthday.getYear(),
baseRandBirthday.getMonth(),
baseRandBirthday.getDayOfMonth()
);
String formattedDate = dateFormat.format(randDate);
birthdays.add(formattedDate);
}
return birthdays;
}
public static void main(String[] args) {
// main method
List<String> bDay = getRandomBirthday(40, 1960, 2022);
System.out.println(bDay);
}
}
I am studying Scala and ended up Googling Java solutions for choosing a random date between range. I found this post super helpful and this is my final solution. Hope it can help future Scala and Java programmers.
import java.sql.Timestamp
def date_rand(ts_start_str:String = "2012-01-01 00:00:00", ts_end_str:String = "2015-01-01 00:00:00"): String = {
val ts_start = Timestamp.valueOf(ts_start_str).getTime()
val ts_end = Timestamp.valueOf(ts_end_str).getTime()
val diff = ts_end - ts_start
println(diff)
val ts_rand = new Timestamp(ts_start + (Random.nextFloat() * diff).toLong)
return ts_rand.toString
} //> date_rand: (ts_start_str: String, ts_end_str: String)String
println(date_rand()) //> 94694400000
//| 2012-10-28 18:21:13.216
println(date_rand("2001-01-01 00:00:00", "2001-01-01 00:00:00"))
//> 0
//| 2001-01-01 00:00:00.0
println(date_rand("2001-01-01 00:00:00", "2010-01-01 00:00:00"))
//> 283996800000
//| 2008-02-16 23:15:48.864 //> 2013-12-21 08:32:16.384
int num = 0;
char[] a={'a','b','c','d','e','f'};
String error = null;
try {
num = Integer.parseInt(request.getParameter("num"));
Random r = new Random();
long currentDate = new Date().getTime();
ArrayList<Student> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
String name = "";
for (int j = 0; j < 6; j++) {
name += a[r.nextInt(5)];
}
list.add(new Student(i + 1, name, r.nextBoolean(), new Date(Math.abs(r.nextLong() % currentDate))));
}
request.setAttribute("list", list);
request.setAttribute("num", num);
request.getRequestDispatcher("student.jsp").forward(request, response);
} catch (NumberFormatException e) {
error = "Please enter interger number";
request.setAttribute("error", error);
request.getRequestDispatcher("student.jsp").forward(request, response);
}

How to calculate a full days difference between two dates considering daylight savings in java

I need to get the full days between two dates in java (the dates are given in Date type) .
For example:
01/01/2015/12:00:00 - 01/02/2015/11:59:00 isn't a full day
and i need to consider daylight savings.
I know that jodatime lib does that but i reached the 65k method limit and i cant use jodatime lib.
i tried the millisecond diff way and the while loop that uses the "before" method:
Android/Java - Date Difference in days
I manage to figure it out:
i used some of this code - https://stackoverflow.com/a/28865648/3873513
and added some of mine:
public static int calcDaysDiff(Date day1, Date day2) {
Date d1 = new Date(day1.getTime());
Date d2 = new Date(day2.getTime());
Calendar date1 = Calendar.getInstance();
date1.setTime(d1);
Calendar date2 = Calendar.getInstance();
date2.setTime(d2);
//checks if the start date is later then the end date - gives 0 if it is
if (date1.get(Calendar.YEAR) >= date2.get(Calendar.YEAR)) {
if (date1.get(Calendar.DAY_OF_YEAR) >= date2.get(Calendar.DAY_OF_YEAR)) {
return 0;
}
}
//checks if there is a daylight saving change between the two dates
int offset = calcOffset(d1, d2);
if (date1.get(Calendar.YEAR) > date2.get(Calendar.YEAR)) {
//swap them
Calendar temp = date1;
date1 = date2;
date2 = temp;
}
return calcDaysDiffAux(date1, date2) + checkFullDay(date1, date2, offset);
}
// check if there is a 24 hour diff between the 2 dates including the daylight saving offset
public static int checkFullDay(Calendar day1, Calendar day2, int offset) {
if (day1.get(Calendar.HOUR_OF_DAY) <= day2.get(Calendar.HOUR_OF_DAY) + offset) {
return 0;
}
return -1;
}
// find the number of days between the 2 dates. check only the dates and not the hours
public static int calcDaysDiffAux(final Calendar day1, final Calendar day2) {
Calendar dayOne = (Calendar) day1.clone(),
dayTwo = (Calendar) day2.clone();
if (dayOne.get(Calendar.YEAR) == dayTwo.get(Calendar.YEAR)) {
return Math.abs(dayOne.get(Calendar.DAY_OF_YEAR) - dayTwo.get(Calendar.DAY_OF_YEAR));
} else {
int extraDays = 0;
while (dayTwo.get(Calendar.YEAR) > dayOne.get(Calendar.YEAR)) {
dayTwo.add(Calendar.YEAR, -1);
// getActualMaximum() important for leap years
extraDays += dayTwo.getActualMaximum(Calendar.DAY_OF_YEAR);
}
return extraDays - day1.get(Calendar.DAY_OF_YEAR) + day2.get(Calendar.DAY_OF_YEAR);
}
}
public class DateDiff {
public static void main(String[] av) {
SimpleDateFormat myFormat = new SimpleDateFormat("MM/dd/yyyy/HH:mm:ss");
String inputString1 = "01/01/2015/12:00:00";
String inputString2 = "01/02/2015/11:59:00";
try {
Date date1 = myFormat.parse(inputString1);
Date date2 = myFormat.parse(inputString2);
long diff = date2.getTime() - date1.getTime(); // Calculate the different
int days = (int) (diff / (1000*60*60*24)); // This convert milliseconds to days
System.out.println ("Days differ: " + days);
} catch (Exception e) {
e.printStackTrace();
}
}
}
The following code will calculate the two dates given, the result print is:
Days differ: 0

Java Check if a given hour and minute lies between two dates' hours and minutes

I have time spans:
long dateStart = System.currentTimeMillis();
long dateEnd = System.currentTimeMillis() + 60*60*1000;
I want to check if mHour and mMinute lies between dateStart and dateEnd.
For example, mHour = 11 and mMinute = 22, so what I want is, dateStart < 11:22 < dateEnd
Here the date does not matter.
Another example:
2014/10/25 15:46 < 10:30 < 2014/10/26 : 15:45, the expected result will be true.
Because, 2014/10/26 10:30 < 2014/10/26 : 15:45
A clarification:
the lower and upper bounds of dateStart and dateEnd cannot exceed 1 day span. So, if dateStart is
2014/10/26 23:59, the most dateEnd would be 2014/10/27 23:58.
I have done this but it did not work out:
compareTime(dateStart ,dateEnd ,mHour ,mMinute );
public static void compareTime(long time1, long time2, int mHour, int mMinute) throws ParseException {
Calendar calendar1 = Calendar.getInstance();
calendar1.setTime(new Date(time2));
Calendar calendar2 = Calendar.getInstance();
calendar2.setTime(new Date(time1));
calendar2.add(Calendar.DATE, 1);
String someRandomTime = selectedHour + ":" + selectedminute;
Date d = new SimpleDateFormat("HH:mm").parse(someRandomTime);
Calendar calendar3 = Calendar.getInstance();
calendar3.setTime(d);
calendar3.add(Calendar.DATE, 1);
Date x = calendar3.getTime();
if (x.after(calendar1.getTime()) && x.before(calendar2.getTime()))
System.out.println(true);
}
It's simply to do with Joda-time library. compareTime method will looks like:
/**
* #param time1 dateFrom in millis. E.g. returned by System.currentTimeMillis()
* #param time2 dateTo in millis
* #param mHour hours in your time zone
* #param mMinute minutes in your time zone
*/
public static boolean compareTime(long time1, long time2, int mHour, int mMinute)
{
final LocalTime timeFrom = new LocalTime(time1);
final LocalTime timeTo = new LocalTime(time2);
final LocalTime time = new LocalTime(mHour, mMinute);
final boolean isSameDay = timeFrom.isBefore(timeTo); // it is correct, because (time2 - time1 < 24 hours)
return isSameDay ? (time.isAfter(timeFrom) && time.isBefore(timeTo))
: (time.isAfter(timeFrom) || time.isBefore(timeTo));
}

Get time with hour, minute, second, millisecond, microsecond

I have this code:
SimpleDateFormat sDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
I know that this code return hour, minute, second in the time.
How i can get also the millisecond and microsecond??
You won't have microseconds, because a Date stores the number of milliseconds since Jan. 1 1970. For the milliseconds, use S, as documented in the javadoc.
The only way to get micro-seconds is to parse the string yourself. Note: Date should be used to store micro-seconds, but you can use a long. (which you can also use for milli-seconds or nano-seconds)
private static final String YEARS_TO_MINUTES = "yyyy-MM-dd HH:mm";
private static final SimpleDateFormat YEARS_TO_MINUTES_SDF = new SimpleDateFormat(YEARS_TO_MINUTES);
public static long parseMicroSeconds(String text) throws ParseException {
long timeMS;
synchronized (YEARS_TO_MINUTES_SDF) {
timeMS = YEARS_TO_MINUTES_SDF.parse(text.substring(0, YEARS_TO_MINUTES.length())).getTime();
}
long microSecs = 0;
if (text.length() > YEARS_TO_MINUTES.length() + 1) {
double secs = Double.parseDouble(text.substring(YEARS_TO_MINUTES.length() + 1));
microSecs = (long) (secs * 1e6 + 0.5);
}
return timeMS * 1000 + microSecs;
}
public static String formatMicroSeconds(long timeMicroSeconds) {
String dateTime;
synchronized (YEARS_TO_MINUTES_SDF) {
dateTime = YEARS_TO_MINUTES_SDF.format(new Date(timeMicroSeconds / 1000));
}
long secs = timeMicroSeconds % 60000000;
return dateTime + String.format(":%09.6f", secs / 1e6);
}
public static void main(String... args) throws ParseException {
String dateTime = "2011-01-17 19:27:59.999650";
long timeUS = parseMicroSeconds(dateTime);
for (int i = 0; i < 5; i++)
System.out.println(formatMicroSeconds(timeUS += 175));
}
prints
2011-01-17 19:27:59.999825
2011-01-17 19:28:00.000000
2011-01-17 19:28:00.000175
2011-01-17 19:28:00.000350
2011-01-17 19:28:00.000525
You can do similarly if you need nano-timings.
The best you can do is:
SimpleDateFormat sDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
You can only show the millisecond: :SS.
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class MyClass
{
public static void main(String args[]) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss:SSSSS");
for(int i=0; i<=5;i++) {
System.out.println("Class 1 : " + ZonedDateTime.now().format(formatter));
}
}
}
Example output:
Class 1 : 19:25:19:77336
Class 1 : 19:25:19:77483
Class 1 : 19:25:19:77487
Class 1 : 19:25:19:77490
Class 1 : 19:25:19:77493
Class 1 : 19:25:19:77496
Check the Java-doc of SimpleDateFormat, it tells :
Millisecond : S
Microseconds are not available.
This example gets millisecond. Microseconds isn't available.
Date someDate = sDate.parse(dateString);
Calendar c = Calendar.setTime(someDate);
int millisecond = c.get(Calendar.MILLISECOND);
Generally the milliseconds are given with capital s and in your case it will be yyyy-MM-dd HH:mm:ss:SSS. For more info refer to Customizing formats

Categories

Resources