How to make time slots using kotlin - android-studio

"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.

Related

Azure Maps Control With Weighted Heat Map Layer

I am creating a web page that has a Heat Map on it using Azure Maps.
I have the heat map successfully pulling in points and displaying, but I need to change how it is rendering.
Specifically my heat map needs to be based on length of time in an area - which can be accomplished by looking at the timestamp that is on my data points. Any ideas on how to accomplish this in the heat map layer using DateTime like values?
The HeatMapLayer class has an option called weight that can take a data driven style expression that provides a number between 0 and 1 to indicate the weight. In your case you are working with timestamps, so you will first want to decide what your time range for min and max values should be. If your timestamps are strings, you should loop through your data before adding it to the data source and calculate the integer value for the data and store it as a property in the feature (i.e. time). For example: new Date('2022-2-14T03:24:00').getTime()
For example, you might want the max value to be anything that has occurred in the current minute (0ms), and the min value to occur on anything that is 15 minutes (900,000ms) or older. You can then put together a formula that makes use of the integer date to get a scalar value between 0 and 1. Here is the math using plain JavaScript:
var timeRange = 900000; //15 minutes
var now = Date.now();
var time = new Date('2022-2-14T03:24:00').getTime();
//Calculate the time offset and snap to the 0 to 15 minute range.
var dt = Math.max(0, Math.min(timeRange, now - time))
//We want the inverse weight since smaller dt should be higher. Thus 1 minus ratio.
var weight = 1 - dt/timeRange;
This can then be turned into a data driven expression and set as the weight value in the heat map layer options.
var timeRange = 900000; //15 minutes
var now = Date.now();
map.layers.add(new atlas.layer.HeatMapLayer(datasource, null, {
weight: ['-', 1, ['/', ['max', 0, ['min', ['-', now, ['get', 'time']], timeRange]], timeRange]]timeRange]]
}), 'labels');
If you want to update the now value periodically you can rebuild the expression and update the heat map using the setOptions function. For example;
var timeRange = 900000; //15 minutes
function getWeightExp(){
var now = Date.now();
return ['-', 1, ['/', ['max', 0, ['min', ['-', now, ['get', 'time']], timeRange]], timeRange]];
}
//Create heatmap layer.
var heatMap = new atlas.layer.HeatMapLayer(datasource, null, {
//Set weight option.
weight: getWeightExp()
});
//Add the heatmap to the map.
map.layers.add(heatMap, 'labels');
//Set an update frequency. In this case once a minute.
setTimeout(function() {
heatMap.setOptions({
weight: getWeightExp()
});
}, 60000);

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
}

Calculate the duration between now and next local time

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);

Query WadPerformanceCountersTable in Increments?

I am trying to query the WadPerformanceCountersTable generated by Azure Diagnostics which has a PartitionKey based on tick marks accurate up to the minute. This PartitionKey is stored as a string (which I do not have any control over).
I want to be able to query against this table to get data points for every minute, every hour, every day, etc. so I don't have to pull all of the data (I just want a sampling to approximate it). I was hoping to using the modulus operator to do this, but since the PartitionKey is stored as a string and this is an Azure Table, I am having issues.
Is there any way to do this?
Non-working example:
var query =
(from entity in ServiceContext.CreateQuery<PerformanceCountersEntity>("WADPerformanceCountersTable")
where
long.Parse(entity.PartitionKey) % interval == 0 && //bad for a variety of reasons
String.Compare(entity.PartitionKey, partitionKeyEnd, StringComparison.Ordinal) < 0 &&
String.Compare(entity.PartitionKey, partitionKeyStart, StringComparison.Ordinal) > 0
select entity)
.AsTableServiceQuery();
If you just want to get a single row based on two different time interval (now and N time back) you can use the following query which returns the single row as described here:
// 10 minutes span Partition Key
DateTime now = DateTime.UtcNow;
// Current Partition Key
string partitionKeyNow = string.Format("0{0}", now.Ticks.ToString());
DateTime tenMinutesSpan = now.AddMinutes(-10);
string partitionKeyTenMinutesBack = string.Format("0{0}", tenMinutesSpan.Ticks.ToString());
//Get single row sample created last 10 mminutes
CloudTableQuery<WadPerformanceCountersTable> cloudTableQuery =
(
from entity in ServiceContext.CreateQuery<PerformanceCountersEntity>("WADPerformanceCountersTable")
where
entity.PartitionKey.CompareTo(partitionKeyNow) < 0 &&
entity.PartitionKey.CompareTo(partitionKeyTenMinutesBack) > 0
select entity
).Take(1).AsTableServiceQuery();
The only way I can see to do this would be to create a process to keep the Azure table in sync with another version of itself. In this table, I would store the PartitionKey as a number instead of a string. Once done, I could use a method similar to what I wrote in my question to query the data.
However, this is a waste of resources, so I don't recommend it. (I'm not implementing it myself, either.)

CouchDB function to sample records at a given interval.

I have records with a time value and need to be able to query them for a span of time and return only records at a given interval.
For example I may need all the records from 12:00 to 1:00 in 10 minute intervals giving me 12:00, 12:10, 12:20, 12:30, ... 12:50, 01:00. The interval needs to be a parameter and it may be any time value. 15 minutes, 47 seconds, 1.4 hours.
I attempted to do this doing some kind of reduce but that is apparently the wrong place to do it.
Here is what I have come up with. Comments are welcome.
Created a view for the time field so I can query a range of times. The view outputs the id and the time.
function(doc) {
emit([doc.rec_id, doc.time], [doc._id, doc.time])
}
Then I created a list function that accepts a param called interval. In the list function I work thru the rows and compare the current rows time to the last accepted time. If the span is greater or equal to the interval I add the row to the output and JSON-ify it.
function(head, req) {
// default to 30000ms or 30 seconds.
var interval = 30000;
// get the interval from the request.
if (req.query.interval) {
interval = req.query.interval;
}
// setup
var row;
var rows = [];
var lastTime = 0;
// go thru the results...
while (row = getRow()) {
// if the time from view is more than the interval
// from our last time then add it.
if (row.value[1] - lastTime > interval) {
lastTime = row.value[1];
rows.push(row);
}
}
// JSON-ify!
send(JSON.stringify({'rows' : rows}));
}
So far this is working well. I will test against some large data to see how the performance is. Any comments on how this could be done better or would this be the correct way with couch?
CouchDB is relaxed. If this is working for you, then I'd say stick with it and focus on your next top priority.
One quick optimization is to try not to build up a final answer in the _list function, but rather send() little pieces of the answer as you know them. That way, your function can run on an unlimited result size.
However, as you suspected, you are using a _list function basically to do an ad-hoc query which could be problematic as your database size grows.
I'm not 100% sure what you need, but if you are looking for documents within a time frame, there's a good chance that emit() keys should primarily sort by time. (In your example, the primary (leftmost) sort value is doc.rec_id.)
For a map function:
function(doc) {
var key = doc.time; // Just sort everything by timestamp.
emit(key, [doc._id, doc.time]);
}
That will build a map of all documents, ordered by the time timestamp. (I will assume the time value is like JSON.stringify(new Date), i.e. "2011-05-20T00:34:20.847Z".
To find all documents within, a 1-hour interval, just query the map view with ?startkey="2011-05-20T00:00:00.000Z"&endkey="2011-05-20T01:00:00.000Z".
If I understand your "interval" criteria correctly, then if you need 10-minute intervals, then if you had 00:00, 00:15, 00:30, 00:45, 00:50, then only 00:00, 00:30, 00:50 should be in the final result. Therefore, you are filtering the normal couch output to cut out unwanted results. That is a perfect job for a _list function. Simply use req.query.interval and only send() the rows that match the interval.

Resources