Calculate the duration between now and next local time - nodatime

I need to determine the duration between now and the next occurrance of a local time. Here's what I've got:
Duration GetDuration(IClock clock, LocalTime time, DateTimeZone zone)
{
// get the current time in this zone
var now = clock.Now.InZone(zone);
// find the time in our zone today
var timeToday = zone.AtLeniently(now.Date + time);
// find the time in our zone tomorrow
var timeTomorrow = zone.AtLeniently(now.Date.PlusDays(1) + time);
// get the next occurrance of that time
var next = new[]{timeToday, timeTomorrow}.Where(x => x > now).Min();
// calculate the duration between now and the next occurance of that time
var duration = next.ToInstant() - now.ToInstant();
Debug.Assert(duration > Duration.Zero);
return duration;
}
And a test to get the duration between now and the next instant of 5PM eastern time:
var duration = GetDuration(
SystemClock.Instance,
new LocalTime(17,00),
DateTimeZoneProviders.Tzdb["US/Eastern"]);
My question is, since I'm new to NodaTime, am I taking any unnecessary steps or missing any shortcuts?

This code is a bit more long-winded than it needs to be - I'd do most of the work in the "local" context, and only convert back to the time zone when you know the LocalDateTime you want to map.
var now = clock.Now.InZone(zone);
// Change this to <= time if you want it to be a "strictly next".
var nextDate = now.TimeOfDay < time ? now.Date : now.Date.PlusDays(1);
return zone.AtLeniently(nextDate + time).ToInstant() - now.ToInstant();
AtLeniently will always return a value which is no earlier than the given LocalDateTime (it returns the later of two ambiguous options, and the start of the interval after a skipped time), so you don't need to worry about DST transitions.
As an aside, feedback about whether the ToInstant() calls in the last line are annoying would be useful. I'd at least consider adding a Duration operator-(ZonedDateTime, ZonedDateTime) to 2.0.

The most easy way is like this:
LocalDate now = LocalDate.now();
LocalDate now2 = now.plusDays(4);
ChronoUnit.DAYS.between(now, now2);

Related

How to make time slots using kotlin

"StartingTime":"11:00",
"EndingTime":"5:00"
Hello,i have a JSON response in which i have these two strings.What i want to do is I want to make time slots using these startingTime and EndingTime.BTW,these two can change for different responses.I want to make time slots with 2 hrs difference between them.Also I want to add an extra 2 hour after the EndingTime.
Example:
Startime = 11:00
EndingTime = 5:00
Time Slots I need = 11:00-1:00 , 1:00-3:00 , 3:00-5:00 , 5:00-7:00
Also once I get this time slots I want to store and add them in a spinner.
How can I achieve it.Thanks.
You can make a simple data class to represent a time slot.
data class TimeSlot(val startTime: LocalTime, val endTime: LocalTime)
And then write a function that splits it up into as many slots that will fit:
fun TimeSlot.divide(lengthHours: Long): List<TimeSlot> {
require(lengthHours > 0) { "lengthHours was $lengthHours. Must specify positive amount of hours."}
val timeSlots = mutableListOf<TimeSlot>()
var nextStartTime = startTime
while (true) {
val nextEndTime = nextStartTime.plusHours(lengthHours)
if (nextEndTime > endTime) {
break
}
timeSlots.add(TimeSlot(nextStartTime, nextEndTime))
nextStartTime = nextEndTime
}
return timeSlots
}
Note, this simple comparison nextEndTime > endTime won't handle a time range that crosses midnight. You'd have to make this a little more complicated if you want to handle that.
You can look up in other existing questions how to parse the JSON values into LocalTimes and how to populate a Spinner from a List.

Socket.io countdown synchronously? [duplicate]

This question already has answers here:
Sync JS time between multiple devices
(5 answers)
Closed 5 years ago.
On my server I call two emits at the same time, which looks like this.
if (songs.length > 0) {
socket.emit('data loaded', songs);
socket.broadcast.to(opponent).emit('data loaded', songs);
}
The one is for opponent and the other for himself.
Once the data is loaded a countdown should appear for both players on my android app. For me it is important that they see the same number at the same time on their screen. To be precise it should run synchronized. How can I do this?
As far as js timers are concerned the will be a small amount of difference. We can reduce the difference in time with reduce of latency time, with the difference between the request and response time from the server.
function syncTime() {
console.log("syncing time")
var currentTime = (new Date).getTime();
res.open('HEAD', document.location, false);
res.onreadystatechange = function()
{
var latency = (new Date).getTime() - currentTime;
var timestring = res.getResponseHeader("DATE");
systemtime = new Date(timestring);
systemtime.setMilliseconds(systemtime.getMilliseconds() + (latency / 2))
};
res.send(null);
}
Elapsed time between sending the request and getting back the response need to be calculated, divide that value by 2. That gives you a rough value of latency. If you add that to the time value from the server, you'll be closer to the true server time (The difference will be in microseconds)
Reference: http://ejohn.org/blog/accuracy-of-javascript-time/
Hope this helps.
I have made an application and I had the same problem. In That case I solved the problem leaving the time control to the server. The server send to the client and the client increases the time. Maybe in your case you could have problem with connection. If the problem exists you can leave clients to increase time by yourself and some times send a tick with correct time for sync.
I could give you something like bellow but I am not tested.
This solution have these steps:
Synchronize timers for client and server. all users have the same difference with server timer.
For the desired response/request get clients time and find the differences with server time.
Consider the smallest as first countdown which will be started.
For each response(socket) subtract the difference from smallest and let the client counter starts after waiting as much as this time.
The client that gets 0 in response data will start immediately.
and the main problem that you may will have is broadcast method which you can't use if you think this solution will be helpful.
This is a post may will help you.
Add time into emit message.
Let's say that songs is an object with {"time" : timeString, "songs" : songsList}.
If we consider devices time is correct You can calculate the time needed for information to travel and then just use server timer as a main calculator.
The client would get the time when countdown should start:
var start = false;
var startTime = 0;
var myTime = new Date().getMilliseconds();
var delay = 1000 - myTime;
setTimeout(function(){
intervalID = setInterval(function(){
myTime = new Date().getTime();
//console.log(myTime); to check if there is round number of milliseconds
if (startTime <= myTime && start = true) {startCountdown();}
}, 100); //put 1000 to check every second if second is round
//or put 100 or 200 is second is not round
}, delay);
socket.on('data loaded', data){
startTime = data.time;
start = true;
}
function startCountdown(){
//your time countdown
}
And that works fine when 2 clients are from same time region, therefore You will need "time converter" to check if time is good due to time difference if You strictly need same numbers.
After the countdown has ended You should clearInterval(intervalID);

setHour without change on Time Zone

I am coding a code on node.js which I need to set hour, minutes, seconds to now date without change time zone. (I get time from client which it sends time in hh:mm:ss format by UTC timezone)
My code on set time is:
var now = new Date();
console.log(now);
now.setHours(format.h);
now.setMinutes(format.m);
now.setSeconds(format.s);
the now time is:
2016-12-30T13:30:17.586Z
and format is:
13:29:29
when I set seconds, the result is
2016-12-30T18:29:29.345Z
It seems the time zone is changing; How can I set hour without timezone change?
UPDATE
I installed the momentjs and here is my code:
var now = moment();
console.log("before: " + now.format());
now.add(format.h, 'hours');
now.add(format.m, 'minutes');
now.add(format.s, 'seconds');
console.log("after: " + now.format());
here is logs:
format time= 3:45:38
before: 2017-01-06T12:55:45+03:30
after: 2017-01-06T16:41:23+03:30
Actually the time should be 2017-01-06T15:45:38+00:00
For any complex date/time manipulation it's better to use moment:
moment().set('hour', 13);
It will save you a lot of headaches.
See: http://momentjs.com/docs/
Instead of
date.setHours()
date.setMinutes()
date.setSeconds()
Use
date.setUTCHours()
date.setUTCMinutes()
date.setUTCSeconds()
And everything will work as expected :)

How to set timezone with moment?

i am using moment for getting server time .
moment.tz.setDefault("Asia/Kolkata");
var now = new Date();
var _p_date = moment.tz(now, zone).format();
time when inserting _p_date = 2016-01-05T18:32:00+05:30
But in database date variable is type of DATETIME. and time is saved as 2016-01-05 18:32:00.
and after that when i comparing with this to get time_ago funcionality. providing me wrong estimation.
using time ago = moment("2016-01-05T18:32:00.000Z").fromNow(); // is showing In 5 hours
Since your initial timezone is lost you have to create moment.tz object with selected timezone. Try this plunker
var date = moment.tz(moment("2016-01-05T18:32:00.000Z", "YYYY-MM-DDTHH:mm")
.format('YYYY-MM-DD HH:mm'), 'Asia/Kolkata');
console.log(date.fromNow());

Comparing Time Strings in Swift

In the app I am making when the view loads I want an object to be deleted in the background whenever the current time is greater than the given time. Otherwise if the current time is less than the given time the object loads normally. This is working fine for any time within the hour for example if the current time is 9:30 PM and the given time is 9:45 PM it works fine, but if the current time is 9:30 PM and the given time is 11:45 PM for some reason it doesn't know how to compare the hour so it doesn't work. Here is my code:
if timeString > End {
self.SpotterMap.removeAnnotation(SpotAnnotation)
let endTime = End
let query:PFQuery = PFQuery(className: "SpotInfo")
query.whereKey("spotendtime", equalTo: endTime)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {
object.deleteInBackground()
}
}
})
print ("spot removed")
}
Can anyone give a solution to my problem?
Thanks
If you are going to work with times, you need to work with the NSDate type representation of your dates for the best accuracy, not a string one.
You will need to change your parse class spotInfo and add a column of type date, lets say you call it "realSpotEndTime".
To compare the times use .compare directly on the NSDates, if the dates return true when ordered ascending, it means that the first date comes before the second one. So your if statement would become;
(note: to get the real current time, you need to instantiate NSDate() right before comparison)
If this returns true and executes it means that the current time on the phone is less compared to the End time, remember, End needs to be in NSDate type as well, not string
let currentTime = NSDate()
//currentTime < End
if (currentTime.compare(End) == .OrderedAscending) {
...
query.whereKey("realSpotEndTime", lessThanOrEqualTo: currentTime)
}
or, alternatively you could do check if the current time is past the end time by
//End < currentTime
if (End.compare(currentTime) == .OrderedAscending) {
// fix parse query here
}

Resources