How to check the number of fixed time segments between two dates? - java

Two Dates are given:
Let's say,
Date dt1 = 22 June 2013 8:00 PM
Date dt2 = 24 June 2013 6:00 AM
Given the two dates, I want to determine that how many segments from 1 am to 5 am are between these two dates.
For above, there are two segments:
23 June 1 am to 5am
24 June 1am to 5am
So the answer should be 2.
I can get the difference between the two times,
var time1 = new Date(dt1).getTime();
var time2 = new Date(dt2).getTime();
var diff = new Date(time1 - time2);
And the number of hours, min and seconds,
var hours = diff.getHours();
var minutes = diff.getMinutes();
var seconds = diff.getMinutes();
But this only gives difference as expected.
What approach is needed to do so ?

Like everything else in computer science: break the problem down into a series of smaller problems that you're able to solve.
For example, in this problem you might simply determine if there's at least one of your "segments" in the time span. If there is, you might remove the first 24 hours from the full time span, then repeat the process for as long as there exists 24 hours to remove. Remember to count along the way.

Another approach might be to check
if time1.getHours() before or equal to 1am then result=1
if time2.getHours() after 5am then resutl++
result+= diff.getDays() - 1

Related

Finding the number of TAI seconds since 00:00:00 UTC, 1 January, 2004 in Java

As the title states, I'm required to find the number of TAI seconds since 00:00:00 UTC, January 1st, 2004 (in Java). I've just recently learned what TAI is and my attempts at working out the above have left me a bit confused.
What I've tried:
I know in Java you can use System.currentTimeMillis() to get the number of milliseconds since January 1st, 1970 UTC (Javadocs).
Additionally, from my brief research of atomic time I understand that currently TAI is exactly 37 (leap) seconds ahead of UTC.
Therefore, my thought process was to:
Find the number of seconds between 1970 and 2004 (34 years)
Subtract that from the current UTC time to get the number of since 2004
Add 37 to get the actual number of seconds in TAI
I wasn't certain of the math here (1 day = 86400 seconds):
Option 1: 86400 (seconds) x 365.25 (days (1 Julian Year)) x 34 (years) = 1,072,958,400
Option 2: 86400 (seconds) x 365 (days (1 Common Year)) x 34 (years) = 1,072,224,000
At this point I started questioning whether the 37 leap seconds added to TAI were to account for leap years when comparing to UTC and thus I should use Option 2. Unfortunately, I'm not certain whether my thought process is correct and I figured it'd be better to ask here to make certain.
Also, I found this cite claiming that 1,072,915,200 (seconds) is equivalent to 01/01/2004 # 12:00am (UTC). Which kind of threw me off because it's not equal to either of my calculations.
Tai-seconds are essentially atomic SI-seconds including leap seconds. My library Time4J supports this feature out of the box. For more details about TAI-support see also the javadoc of class Moment:
Moment m2004 = PlainTimestamp.of(2004, 1, 1, 0, 0).atUTC();
Moment now = SystemClock.currentMoment(); // other clocks based on NTP are possible
long seconds = SI.SECONDS.between(m2004, now);
System.out.println(seconds); // 425222084L
System.out.println(now); // 2017-06-22T13:15:24,570000000Z

Is datastore good for storing hr shifts?

everyone.
I'm trying to figure out if Google Datastore is the best option in my case..
I need to store employees with theirs schedules like:
id
name
schedule
Schedule looks like:
Mon 10am-10pm (simple)
Tue 10am-5pm, 5.30pm-8pm (multiple, not even hours)
..
Sun 6pm-4am (start/end are in different days)
one of the APIs returns if employee is working NOW or not
I tried to play with datastore but GQL queries appeared to be very limited, for example you cant compare in one query two different properties (like
.. WHERE current_time>start_time AND current_time<close_time
You cannot use inequality operators (less than, more than, etc.) on
different property names in the same query.
It means that I need to load lots of entities into my backed and parse them, wasting time and resources.. instead of getting results right from database
Is there any way to use datastore for my task? or its better to go sql?
how to design my database to store schedules in datasore/sql?
thanks in advance!
Based on your examples, I'm going to assume work shifts are in 30 min increments. If that is not the case you can adjust the below easily, although you may want to consider some optimizations.
The below solution will give you constant time look-ups for employees, regardless of how many shifts they work. It also seamlessly handles shifts that go from one day to the next.
0. Your entity model
I'm going to use the following straw man entity
Entity Kind: Employee
- id: Auto id
- name: string
- schedule: repeated integer, indexed
2. Break day into 30 minute blocks
24 hours gives you 48 periods of 30 minutes, so let's map integers to time periods:
0 = 12:00 AM to 12:30 AM
30 = 12:30 AM to 1:00 AM
60 = 1:00 AM to 1:30 AM
...
1380 = 11:00 PM to 11:30 PM
1440 = 11:30 PM to 12:00 AM
This integer is easy to derive from your current time. Using java.util.Calendar and java.util.Date:
Date date = new Date(); // Initializes to now.
Calendar calendar = GregorianCalendar.getInstance();
calendar.setTime(date);
int hour = calendar.get(Calendar.HOUR_OF_DAY); // Hour in 24h format
int minute = calendar.get(Calendar.MINUTE); // Minute of the hour
int period = hour*60 + minute/30*30; // Integer division rounds down to nearest 30
I tested this on compilejava.net, test code here: https://gist.github.com/55a98bbdb9b5eb3eeaee5f8984f11687
3. Account for day of week
Now we have 30 minute period blocks in the day, we should merge in the day of the week (Sunday = 0, Saturday = 6). Since the max 30 min period value is 1440, it is convenient to just multiple the day of the week by 10000 so we can add them together without conflict:
int day = calendar.get(Calendar.DAY_OF_WEEK);
int day_period = day*10000 + period;
Expanded test code here: https://gist.github.com/217221e03b3eb143b4be45bf3f641d25
4. Storing the Schedule
Now, instead of storing your schedule as start and stop times per day, use the same idea above to store each 30 minute period that an Employee is scheduled for. In your example you had:
Mon 10am-10pm (simple)
Tue 10am-5pm, 5.30pm-8pm (multiple, not even hours)
..
Sun 6pm-4am (start/end are in different days)
In the schedule field (repeated integer), this would look like:
10600,10630,10660,10690,10720,10750,10780,10810,10840,10870,10900,10930,10960,10990,11020,
11050,11080,11110,11140,11170,11200,11230,11260,11290,20600,20630,20660,20690,20720,20750,
20780,20810,20840,20870,20900,20930,20960,20990,21050,21080,21110,21140,21170,1080,1110,
1140,1170,1200,1230,1260,1290,1320,1350,1380,1410,0,30,60,90,120,150,180,210
5. Query time!
Querying is extremely easy now and merely an equality. This will give you O(1) performance per Employee entity working right now, or more generally O(n) where n is the number of employees that are working now (as opposed to total employees).
... WHERE schedule=day_period
You can store long representation of the start time and end time. 1 hour = 3600000 milliseconds. So if 00-00 is the reference point 02-00 will be represented by 2 x 3600000 . Another option is to store java.util.Date (one for start time and one for end time)

need to find every X minutes between to hours

I have two hours lets say 12:00 and 14:00 (the input will always be two hours of "whatever" day) second time will always be greater than first time. So the input is simple : two given times in a day. I need to find every 30 minutes between those two times.
I need the following output (the ellapsed time between each output will always be 30 minutes in my case:
12:00
12:30
13:00
13:30
14:00
14:30
I am discovering jodatime but I am a bit confused with how the determine "startTime" and "end Time"
It's pretty easy, actually:
DateTime current = start;
while(true){
System.out.println(current);
current=current.plusMinutes(30);
if(current.isAfter(stop))break;
}
Responding to comment:
to parse a String, you need a DateTimeFormatter. Here's one of several ways to acquire one:
private static final DateTimeFormatter DATE_TIME_FORMATTER =
DateTimeFormat.forPattern("HH:mm");
Now you can do:
DateTime startDate = DATE_TIME_FORMATTER.parseDateTime(startString);

Java - get differences between given fortnight and current fortnight

For example:
Data Given :
Year-2010,
Month-2,
Fortnight-1
Current date
How do I get the difference in terms of number of fortnights between the two given dates?
This is what I figured out and its working fine...
Calendar c= Calendar.getInstance();
int year = 2011;
int month = 6;
int fortnight = 1;
int noofmonths=(c.get(Calendar.YEAR)-year)*12;
noofmonths=(noofmonths+((12-(month-1)+(c.get(Calendar.MONTH)-12)))-1)*2;
int nooffortnights=noofmonths+((2-(fortnight-1)+((c.get(Calendar.DAY_OF_MONTH)<15?1:2)-2)))-1;
System.out.println("nooffortnights : "+nooffortnights); //outputs 5
This depends on your definition of fortnights. If we are literal minded then a fortnight is defined as 14 days, so compute the number of days and divide by 14, job done.
I suspect that in your case we are actually using a special business calendar, where fortnights are a subdivision of quarters and hence there are some special cases - a year doesn't exactly divide into fortnights and perhaps the business year does not start on Jan 1st? So somewhere there will be a definitive list of the dates of the start of each fortnight in a year.
Let's suppose that the fortnight definitions have
17th Nov - 1st Dec
2nd Dec - 15th Dec
16th Dec - 31st Dec (note this is 15 days long)
Now what's the definition on how many fortnights from 17th Nov to 16th Dec? I guess 2. From 19th Nov to 16th Dec? I have no idea what answer you would expect.
So first, get really clear what the business requirements are. I'd be surprised is you will find off-the-shelf date packages that understand fortnights, but even if you do you need to check very carefully that they give the answers you need.
Assuming you want to do this without any 3rd Party libraries
Make 2 Calendar Objects (both with the given dates).
Calendar c1 = Calendar.getInstance(),c2 = Calendar.getInstance();
c1.add(Calendar.MONTH, 2);
int fortnights = (int)((c1.getTimeInMillis() - c2.getTimeInMillis()) / (14L * 24 * 60 * 60 * 1000));
System.out.println(fortnights); //output should be 4
Note, it's a rough approximation.

calculate frequency on certain range

I have maths problem ... (at the moment i solved it using manual iteration which is pretty slow) ...
For example if an employee got paid weekly (it can be fortnightly / every 2 weeks and monthly) with certain date (let's call the employee got paid every tuesday and for monthly the employee paid on certain date).
I have date range between 10th August 2009- 31 December 2009, now how to get frequency the employee got paid ?
is it possible to calculate this using jodatime ?
Example to make this question clear:
I have date range between Friday 14 August - Monday 14 Sept 2009 (31 days)
the employee got paid on every Tuesday
so he got paid on 18 & 25 August, 1 & 8 August we got 4 times payment
(frequency)
another example:
with the same date range Friday 14 August - Monday 14 Sept 2009 (31 days)
but different pay date .. for example on Sunday
so he got paid on : 15, 22 & 29 August , 5 & 12 September ... we got 5 times payment.
same date range but different pay day .. will result different.
So my question is, are there any formula to solve this case ?
at the moment I calculate using manual iterator .. which is very slow (because the range could be some years or months)
thank you
ps: I am using groovy .. any solutions using java or groovy or just algorithm are welcome :)
Oftentimes pay periods are on the 15th and the end of every month, so in that case you'd count the number of months and multiply by 2, checking the end conditions (if start is before the 15th, subtract one pay period; if end is after end of the month subtract one pay period).
It's possible to get counts of days, weeks, and months, but you'll have to add in the logic to handle the dodgy end conditions. It's probably not a simple formula, as the case I described demonstrates.
abosolutely, using the Weeks class is very simple:
DateTime start = new LocalDate(2009, 8, 10).toDateTimeAtStartOfDay();
DateTime end = new LocalDate(2009, 12, 31).toDateTimeAtStartOfDay();
int numberOfWeeks = Weeks.weeksBetween(start, end).getWeeks();
this code give 20 as result. It is right?
EDIT
maybe this is better:
DateMidnight start = new DateMidnight(2009, 8, 10);
DateMidnight end = new DateMidnight(2009, 12, 31);
int numberOfWeeks = Weeks.weeksBetween(start, end).getWeeks();
System.out.println(numberOfWeeks);
Subtracting one date from the other to get the "number of days" (or weeks) is generally the wrong way to go for these kinds of calculations. For example, if someone is 365 days old, they are exactly one year old, unless there was a February 29 during that time. In any (modern) 7-day period, there is always exactly one Tuesday; but for 8 days, it's either one or two. The calendar often figures into the calculations.
If they're paid once or twice a month, you do the easy calculation on the whole months -- starting on the first and ending on the last day of the month, which varies -- and then you have to consider partial months at the beginning and/or end. (Don't forget what happens if the 15th or last day of the month falls on a weekend.) If they're paid every one or two weeks, you can sync on a known payday, and then do the simpler math to figure the whole weeks before and/or since. (Don't forget holidays that fall on the payday.)
There are two tricks here: One is that the rules are different depending on the time frame. I mean, if a person is paid once a week, then in 7 days he gets paid once, in 14 days he gets paid twice, etc. But if a person is paid on the 1st and 16th of every month, I can't tell you how many times he was paid in 60 days without knowing what months were included: where they short months or long months?
The second is that you have to worry about the start and end of the time period. If a person is paid every Monday, then the number of times he gets paid in 8 days depends on whether the first day of the 8 is Monday.
Thus, I think you need to have different logic for schedules that are a fixed number of days and those that are tied to months or something else where the intervals can vary.
For the fixed number of days, the problem is fairly simple. The only complexity is if the time frame is not an exact multiple of the interval. So I'd say, find the first date in the interval on which a payday occurs. Then find the number of days between there and the end of the time period, divide by the interval and drop any fractions.
For example: A person is paid every Monday. How many pay days between March 1 and April 12? Find the first Monday in that range. Say it falls on March 4. Then calculate the number of days from March 4 to April 12. That would be 39. 39/7=5 and a fraction. Therefore he gets paid 5 more paychecks, for a total of 6.
For monthly pay, I think you'd have to separate out the first and last month. You could then count the number of months in the middle and multiply by the number of pays per month. Then for the first and last count how many are in them the hard way.
Just got solutions please check if I did something wrong
import org.joda.time.* ;
def start = new Date().parse("dd/MM/yy","14/08/2009");
def end = new Date().parse("dd/MM/yy","14/09/2009");
println("date range ${start} - ${end}");
def diff = end - start ;
println("diff : ${diff} days ");
println("how many weeks : ${diff/7}");
def payDay = 2 ; // Monday = 1 Sunday = 0
def startDay = new DateTime(start).dayOfWeek ; // 5 = Thursday
def startDayDiff = payDay - startDay ;
if(startDay > payDay){
startDayDiff = 7 + payDay - startDay ;
}
// for example if end on Friday (5) while Pay day is day 1 (Monday) then
// make sure end date is on Monday (same week )
// end date = end - ( endDay - payDay)
def endDay = new DateTime(end).dayOfWeek;
println("original end day: ${endDay}");
def endDayDiff = endDay - payDay ;
// otherwise ... if endDay < payDay (for example PayDay = Friday but End day is on Monday)
// end date = end - 7 + payDay
if(endDay < payDay){
endDayDiff = 7 - endDay - payDay ;
}
println("endDayDiff : ${endDayDiff}");
println("startDayDiff: ${startDayDiff}");
def startedOn = new DateTime(start).plusDays(startDayDiff);
println("started on : ${startedOn.toDate()}");
def endOn = new DateTime(end).minusDays(endDayDiff);
println("End on : ${endOn.toDate()}");
println("occurences : ${Weeks.weeksBetween(startedOn,endOn).getWeeks()+1}");
Tested using groovyConsole with Joda Time help .. :)

Categories

Resources