I am setting up a db40 database, and it is filled with instances of my class Day() which has sales information for that day in history, and an integer for its ID.
The id is formatted like so: YYYYMMDD, so that they are all unique. My db is set up with the correct data chronologically, but right now I am forced to go in and edit the id's manually for over a year's worth of data.
Question: assuming day 1 is January 1, 2014 which would be formatted: 20140101, how do I correctly increment the date by one day each time? I have 424 dates I need to calculate after that, but I can't think of a clever solution without brute forcing it.
So ideally, i would want something like this getDate(ThisDate+1 Day)
As you're using Java 8, I'd use java.time for this:
Convert the integer (ick) into a LocalDate
Add however many days you want
Convert back to an integer (ick)
So something like:
static LocalDate dateFromId(int id) {
int year = id / 10000;
int month = (id / 100) % 100;
int day = id % 100;
return LocalDate.of(year, month, day);
}
static int idFromDate(LocalDate date) {
return date.getYear * 10000
+ date.getMonthValue() * 100
+ date.getDayOfMonth();
}
static int advanceId(int id, int days) {
LocalDate original = dateFromId(id);
LocalDate advanced = original.plusDays(days);
return idFromDate(advanced);
}
Or to compute a bunch of them:
LocalDate original = dateFromId(id);
for (int i = 1; i <= count; i++) {
LocalDate advanced = original.plusDays(i);
int advancedId = idFromDate(advanced);
// Use advanced
}
Related
I am implementing a service (not going to production anywhere anytime) which should receive a LocalDateTime and a Duration and should check if given time is between company working hours (which are 8:00-22:00), the working hours should be (somehow) configurable:
lets say that I have a:
public class CompanyWorkingHoursService {
private static final Int OPENING_HOUR = 8;
private static final Int CLOSING_HOUR = 22;
private boolean isMeetingBetweenWorkingHours(LocalDateTime beginningDateTime, Duration duration) {
LocalDateTime endingDateTime = beginningDateTime.plus(duration);
}
and I'm stuck.
I can change the type of OPENING_HOUR and CLOSING_HOUR to whatever I want. I can get hours and minutes from LocalDateTime but those are integers. And I don't want to compare whole dates - i need just hours and minutes.
I have found some solutions using java.util.Date but I would like to stay with LocalDateTime if possible...
The "best" thing is to avoid integers. So define the opening and closing hours as LocalTime, and compare the dates using the isAfter(), isBefore() and equals() provided by LocalTime:
private static final LocalTime OPENING_HOUR = LocalTime.of(8, 0);
private static final LocalTime CLOSING_HOUR = LocalTime.of(22, 0);
private boolean isMeetingBetweenWorkingHours(LocalDateTime beginningDateTime, Duration duration) {
LocalDateTime endingDateTime = beginningDateTime.plus(duration);
return !beginningDateTime.toLocalTime().isBefore(OPENING_HOUR)
&& !endingDateTime.toLocalTime().isAfter(CLOSING_HOUR));
}
If the working hours should be (somehow) configurable, you could pass them to the method, too. Afterwards create LocalDateTime instances from those values in combination with the date of the meeting.
Maybe like this:
public static boolean isMeetingBetweenWorkingHours(
LocalDateTime startMeeting, Duration meetingDuration,
int openFrom, int openUntil) { // pass start and end hour of day
/*
* create the working time hours using the hours of day passed
* and using the date of the meeting start passed
*/
LocalDateTime startWorkingHours = LocalDateTime.of(startMeeting.toLocalDate(),
LocalTime.of(openFrom, 0));
LocalDateTime endWorkingHours = LocalDateTime.of(startMeeting.toLocalDate(),
LocalTime.of(openUntil, 0));
// calculate the end time of the meeting
LocalDateTime endMeeting = startMeeting.plus(meetingDuration);
// then return if the meeting fully fits into the working time slot
return !startMeeting.isBefore(startWorkingHours)
&& !endMeeting.isAfter(endWorkingHours);
}
I need to find the day of the week (i.e. Monday, Tuesday...) given MM-DD-YYYY. So basically what java calendar would do, but without using java calendar.
It is possible, though unusual, to compute a number that corresponds to the day of the week from a calendar date.
In brief, you will first need to calculate a serial date number from the calendar date, i.e. a number that is a continuous count of days that have elapsed since a certain fixed point in time (informally called 'the epoch'). The most commonly encountered serial date scheme encountered in modern computing is Posix Time, which has an epoch date of Jan 1, 1970 at midnight UTC.
You will need to decide what level of precision is needed for this calculation, eg. whether you will need to account for the Julian Calendar (used in most of Europe before the Gregorian Calendar reform by Pope Gregory in 1584), whether to correct for century days, etc.
Several algorithms are available to arithmetically convert a calendar date to a serial date number with a given epoch. Historically, the most commonly used epoch for these calculations has been the Julian Day number system (not to be confused with the Julian Calendar), which counts days from November 24, 4714 BC in the proleptic Gregorian calendar. Below is Java code which implements one such algorithm published by Jean Meeus in his book "Astronomical Algorithms, 2nd Ed." This algorithm computes a Julian Day number and assumes that days are exactly 86400 seconds in length, accounts for the general Gregorian Reform, and accounts for century and leap days:
public class JulianDay {
private static final int YEAR = 0;
private static final int MONTH = 1;
private static final int DAY = 2;
private static final int HOURS = 3;
private static final int MINUTES = 4;
private static final int SECONDS = 5;
private static final int MILLIS = 6;
:
:
// Converts a timestamp presented as an array of integers in the following
// order (from index 0 to 6): year,month,day,hours,minutes,seconds,millis
// month (1-12), day (1-28 or 29), hours (0-23), min/sec (0-59) to a
// Julian Day Number.
// For clarity and simplicity, the input values are assumed to be well-formed;
// error checking is not implemented in the snippet.
public static double toJD(int[] ymd_hms) {
int y = ymd_hms[YEAR];
int m = ymd_hms[MONTH];
double d = (double) ymd_hms[DAY];
d = d + ((ymd_hms[HOURS] / 24.0) +
(ymd_hms[MINUTES] / 1440.0) +
(ymd_hms[SECONDS] / 86400.0) +
(ymd_hms[MILLIS] / 86400000.0));
if (m == 1 || m == 2) {
y--;
m = m + 12;
}
double a = Math.floor(y / 100);
double b = 2 - a + Math.floor(a / 4);
return (Math.floor(365.25 * (y + 4716.0)) +
Math.floor(30.6001 * (m + 1)) +
d + b - 1524.5);
}
}
Once you have a serial date number, it is straightforward to compute the day of the week from the remainder when the date number is divided by 7 (the number of days in a week).
If you are talking about simply avoiding the Calendar Object then you could use the Date Object (deprecated) but still works and call setMonth, setYear, and setDate to get the desired date. You then have to use a DateFormatter to get your desired output. I used a SimpleDateFormat and the E specifier to get the day of the week.
Date dNow = new Date();
SimpleDateFormat ft = new SimpleDateFormat ("E");
System.out.println("Current Date: " + ft.format(dNow));
This outputs the current day of the week "Sun", "Sat", etc..
This link will help with the formatting https://www.tutorialspoint.com/java/java_date_time.htm
java.time
Using the java.time classes that supplant the troublesome old date-time classes. The LocalDate class represents a date without a time-of-day and without a time zone.
DayOfWeek dow =
LocalDate.parse(
"01-23-2016" ,
DateTimeFormatter.ofPattern( "MM-dd-uuuu" )
).getDayOfWeek()
That code returns a DayOfWeek enum object. From there you can interrogate for:
Integer number, 1-7 for Monday-Sunday
Localized name of the day.
Example code.
int dowNumber = dow.getValue() ;
String dowName = dow.getDisplayName(
TextStyle.FULL ,
Locale.CANADA_FRENCH ) ; // Or Locale.US, Locale.ITALY, etc.
TIP: Pass around the DayOfWeek objects themselves in your own code, rather than internally track the day-of-week as a number or string. This makes your code more self-documenting, ensures valid values, and provides for type-safety.
I was looking for the answer myself and found another answer based on Zeller's algorithm:
// d = day in month
// m = month (January = 1 : December = 12)
// y = 4 digit year
// Returns 0 = Sunday .. 6 = Saturday
public int dow(int d, int m, int y) {
if (m < 3) {
m += 12;
y--;
}
return (d + int((m+1)*2.6) + y + int(y/4) + 6*int(y/100) + int(y/400) + 6) % 7;
}
Source: here
I'm storing measurements in a MySQL database.
The measurements contain a timestamp field which stores timestamps in the following format:
2015-10-10 10:10:10.11 (so with two digits of milliseconds)
In my Java code I retrieve this value with:
resultSet.getTimestamp(id)
When I print this value it gives me:
2015-10-10 11:11:11.000000011
So I'm trying to figure out WHY it behaves like this and HOW I should solve this issue so I get the right value?
EDIT:
The values show correctly inside the database itself when using select * from measurement
My guess it should be somewhere in the way it is retrieved by Java / JDBC.
Both getTimestamp and getString give me the same result.
EDIT 2:
resultSet = statement.executeQuery("select * from measurement");
Measurement m;
while(resultSet.next()) {
m = new Measurement(
resultSet.getString(1),
resultSet.getString(2),
resultSet.getDouble(4),
resultSet.getTimestamp(3));
System.out.println(m);
}
I've never been a fan of how MySQL's JDBC driver deals with the TIMESTAMP type. I'd use:
select ROUND(UNIX_TIMESTAMP(col1)*1000) FROM measurement
And then read it with
java.util.Date d = new java.util.Date(resultSet.getLong(1));
I've been looking into the implementation. Even though it's a bit over my head I found out some 'interesting' information.
The implementation of com.mysql.jdbc.ResultSet.getTimestamp() has some clues:
int year = 0;
int month = 0;
int day = 0;
int hour = 0;
int minutes = 0;
int seconds = 0;
int nanos = 0; <<< CLUE
and
if (numDigits < 9) {
int factor = (int) (Math.pow(10, 9 - numDigits));
nanos = nanos * factor;
}
and
TimeUtil.fastTimestampCreate(tz, year, month, day, hour, minutes, seconds, nanos);
So it seems to parse everything after the '.' as nanoseconds ending up with leading zeroes. so .11 becomes .000000011.
So I think this explains the WHY it is happening...
The HOW to fix this could be in many ways, some being:
Getting the UNIX_TIMESTAMP as user5449350's answer.
Storing UNIX_TIMESTAMPS instead of TIMESTAMP / DATETIME
Correct the faulty Date object and correct it using Calendar
Date t = resultSet.getTimestamp(3);
Calendar c = Calendar.getInstance();
c.setTime(t);
c.set(Calendar.MILLISECOND, ((Timestamp)t).getNanos());
t = c.getTime();
I am trying to get the days between two values. Which is in the format of MMdd.
Ex:
First Date = 0501
Second Date = 0519
Trying to find the value of days between the two dates. In this example would be 18. Please help me with this. I tried searching around and can't find a solution. Thank you!
My Code
This is what I have so far:
Getting an error: Method days in class Project3 cannot be applied to the given type.
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;
public class Project3 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String name = input.next() + input.nextLine();
String car = input.next() + input.nextLine();
String key = input.next();
String firstDate = input.next(), lastDate = input.next();
double S = 1.0, C = 1.2, U = 1.4, T = 1.6, B = 2.0;
final double N = 89.22, V = (N - 11.4);
double daily, total;
String daysBetween = Project3.days();
}
public static long days(Date firstDate, Date lastDate) {
Calendar start = Calendar.getInstance();
start.setTime(firstDate);
Calendar end = Calendar.getInstance();
long daysBetween = 0;
while (start.before(end)) {
start.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}
}
Using Joda Time Days:
DateTimeFormatter dtf = DateTimeFormat.forPattern("MMdd");
LocalDate day1 = dtf.parseLocalDate("0501");
LocalDate day2 = dtf.parseLocalDate("0519");
int daysBetween = Days.daysBetween(day1, day2).getDays();
Joda time is the right way to do this, but if you really have to do it with pure JDK stuff, you can calculate it yourself.
A Calendar instance has a .getTimeInMillis() method that tells you the number of milliseconds since some fixed start point. You can take two dates, put them into Calendar instances, and then calculate the difference between the two getTimeInMillis() values.
Then divide by 1000 to get seconds; by 60 to get minutes; by 60 to get hours; by 24 to get days. And cross your fingers and hope for the best with regard to daylight saving time.
You have one other issue to get round, which is that since you've only got a day and a month, but not a year, there isn't a unique answer. The difference in days between 28 Feb and 1 Mar is one day in most years, but two days in a leap year. If you want to assume Feb has only 28 days, just choose any non-leap year you like (e.g., 2014).
This is a method for calculating the number of days between two dates. It keeps rolling the day forward, while the start date is before the end date. It works regardless of differences in time due to daylight saving time.
public static long days(Date startDate, Date endDate) {
Calendar start = Calendar.getInstance();
start.setTime(startDate);
Calendar end = Calendar.getInstance();
long daysBetween = 0;
while(start.before(end)) {
start.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}
I have two dates, hiring 11/19/2013 and endhiring 10/01/2014, both are converted to total hours, without considering the weekends, but they have different years and because of this the output says: the total hours worked was -1200:
private int calculateTimeInternship(Vacancy peoplevacancy){
int hourWorked = 0;
Calendar date1 = Calendar.getInstance();
Calendar date2 = Calendar.getInstance();
date1.setTime(peoplevacancy.getDthiring());
date2.setTime(peoplevacancy.getDtendhiring());
int initiation = date1.get(Calendar.DAY_OF_YEAR);
int end = date2.get(Calendar.DAY_OF_YEAR);
int amountDay = (initiation - end) + 1;
for (; initiation <= end; inicio++){
if (date1.get(Calendar.DAY_OF_WEEK) == 1 || date1.get(Calendar.DAY_OF_WEEK) == 7)
amountDay--;
date1.add(Calendar.DATE, 1);
}
hourWorked = amountDay * 4 //4 hour per day;
return hourWorked ;
}
Joda can help you, but I'm never able to use it because of its license.
If like me, Joda is not appropriate for you, you can solve this problem as follows:
initialize endDate object
initialize startDate object
initialize weeksBetween as
milliseconds between end&start/milliseconds per day, divided by seven (integer floor).
//may need to normalize dates and set them to be both midnight or noon or some common time
initialize daysBetween = weeksBetween*5 // in any continuous 7 days, 5 are weekdays.
initialize curDay=startDate + weeksBetween*7 days
while(curDay is not endDate)
add a day to curDay
if(curDay is not weekend)
daysBetween++
output daysBetween* 4
You can get the milliseconds between them by converting the calendars to Date (Calendar has such a method to do this)
You are already looping through every day of the internship, so why not simply count workdays?
int amountDay = 0;
while (date1.compareTo(date2) <= 0) {
if (date1.get(Calendar.DAY_OF_WEEK) != 1
&& date1.get(Calendar.DAY_OF_WEEK) != 7)
amountDay++;
date1.add(Calendar.DATE, 1);
}
By the way, your original code has a subtle "off by one" bug. The subtraction for the total amountDays excludes the end day, but the loop includes the end day when deducting weekends.
Why so complicated?
private int calculateTimeInternship(Vacancy vacancy) {
return 4 * ((int)(vacancy.getDtendhiring().getTime() / 86400000L - vacancy.getDthiring().getTime() / 86400000L) + 1);
}
By dividing by 86400000 first, then subtracting, it doesn't matter what time of day each date have.
FYI 86400000 is the number of milliseconds in a day.