Rounding seconds of time with HH:MM:SS format to nearest minute - flutter

For Example: Sunset-Sunrise.org provides sunset/sunrise time with HH:MM:SS format.
Given a time such as 12:53:57, I want to round the seconds to 12:54:00. Please advise.

A general technique for rounding is to add half of the unit you want to round to and then truncating. For example, if you want to round an integer to the nearest ten's digit, you can add 5 and discard the one's digit: ((x + 5) ~/ 10) * 10.
The same technique works for times too. You can first parse the HH:MM:SS string into a DateTime object. Then, to round the DateTime to the nearest minute, you can add 30 seconds and copy all of the resulting fields except for the seconds (and subseconds):
DateTime roundToMinute(DateTime dateTime) {
dateTime = dateTime.add(const Duration(seconds: 30));
return (dateTime.isUtc ? DateTime.utc : DateTime.new)(
dateTime.year,
dateTime.month,
dateTime.day,
dateTime.hour,
dateTime.minute,
);
}

You can use date_time_fromat packages
from the docs
final timeOffset = dateTime.subtract(Duration(hours: 6, minutes: 45));
// 7 hours
print(DateTimeFormat.relative(timeOffset));
// 6 hours
print(DateTimeFormat.relative(timeOffset, round: false));
This is the URL

Related

Flutter - Convert minutes to TimeOfDay

Currently I get a number from the BE that states like 750 minutes (int) and should represent the time of day.
750 minutes = 12.5 hours and so the UI should display 12:30
1080 minutes = 18 hours and so the UI should display 18:00
But I can't seem to find a way to get a clean convertion from minutes to a proper Object with hours and minutes.
In the end I want to have a TimeOfDay object
I will continue to struggle and will also post if I find the answer myself :)
With the help of the comments above I resolved it by splitting the sting. I don't see this as the best way to convert since I'm dependened that the Duration Class will never change but never the less I got what I wanted by doing the following
TimeOfDay minutesToTimeOfDay(int minutes) {
Duration duration = Duration(minutes: minutes);
List<String> parts = duration.toString().split(':');
return TimeOfDay(hour: int.parse(parts[0]), minute: int.parse(parts[1]));
}
Create Duration with the amount of minutes, then toString() that instance this will outpout 00:00 and then split this string on the colon ":"
I suggest doing two mathematical operations like this:
TimeOfDay minutesToTimeOfDay(int minutesPastMidnight) {
int hours = minutesPastMidnight ~/ 60;
int minutes = minutesPastMidnight % 60;
return TimeOfDay(hour: hours, minute: minutes);
}
This is roughly based on this answer to a related question.

Result of adding second to date is one minute off; workaround

I'm adding a second to an instance of Foundation's date, but the result is off by an entire minute.
var calendar = Calendar(identifier: .iso8601)
calendar.locale = Locale(identifier: "en")
calendar.timeZone = TimeZone(identifier: "GMT")!
let date1 = Date(timeIntervalSinceReferenceDate: -62544967141.9)
let date2 = calendar.date(byAdding: DateComponents(second: 1),
to: date1,
wrappingComponents: true)!
ISO8601DateFormatter().string(from: date1) // => 0019-01-11T22:00:58Z
ISO8601DateFormatter().string(from: date2) // => 0019-01-11T21:59:59Z
Interestingly, one of the following makes the error go away:
round time interval since reference date
don't add time zone to calendar
set wrappingComponents to false (even though it shouldn't wrap in this case)
I don't really need sub-second precision in my code, so I created this extension that allows me to discard it.
extension Date {
func roundedToSeconds() -> Date {
return Date(timeIntervalSinceReferenceDate: round(timeIntervalSinceReferenceDate))
}
}
I want to know this:
Why does this error happen?
Am I doing something wrong?
Is there any issue with my workaround?
Why does this error happen?
I would say this is a bug in Core Foundation (CF).
Calendar.date(byAdding:to:wrappingComponents:) calls down to the internal Core Foundation function _CFCalendarAddComponentsV, which in turn uses the ICU Calendar C API. ICU represents a time as an floating-point number of milliseconds since the Unix epoch, while CF uses a floating-point number of seconds since the NeXT reference date. So CF has to convert its representation to ICU's representation before calling into ICU, and convert back to return the result to you.
Here's how it converts from a CF timestamp to an ICU timestamp:
double startingInt;
double startingFrac = modf(*atp, &startingInt);
UDate udate = (startingInt + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
The modf function splits a floating-point number into its integer and fractional parts. Let's plug in your example date:
var startingInt: Double = 0
var startingFrac: Double = modf(date1.timeIntervalSinceReferenceDate, &startingInt)
print(startingInt, startingFrac)
// Output:
-62544967141.0 -0.9000015258789062
Next, CF calls __CFCalendarAdd to add one second to -62544967141. Note that -62544967141 lies in the round one-minute interval -62544967200 ..< -62544967140.0. So when CF adds one second to -62544967141, it gets -62544967140, which would be in the next round one-minute interval. Since you specified wrapping components, CF isn't allowed to change the minute part of the date, so it wraps back to the beginning of the original round one-minute interval, -62544967200.
Finally, CF converts the ICU time back to a CF time, adding in the fractional part of the original time:
*atp = (udate / 1000.0) - kCFAbsoluteTimeIntervalSince1970 + startingFrac + (nanosecond * 1.0e-9);
So it returns -62544967200 + -0.9000015258789062 = -62544967200.9, exactly 59 seconds earlier than the input time.
Am I doing something wrong?
No, the bug is in CF, not in your code.
Is there any issue with my workaround?
If you don't need sub-second precision, your workaround should be fine.
I can reproduce it with more recent dates but so far only with negative reference dates, e.g. Date(timeIntervalSinceReferenceDate: -1008899941.9), which is 1969-01-11T22:00:58Z.
Any negative timeIntervalSinceReferenceDate in the last second of a minute interval should cause the problem. The bug effectively makes the first round whole minute prior to time 0 span from -60.99999999999999 through -1.0, but it should span from -60.0 through -5e324. All more-negative round minute intervals are similarly offset.

add incremnting seconds to time in HH:mm:ssPM format

How to add a vector of seconds to time HH:mm:ssPM in MATAB?
I usually have this nice way in Excel to convert normal number format to hour and minutes and sec. format using simple cell custom formatting, but when I put down code below in MATLAB, instead of incrementing in seconds, it adds in days!
time = 1+0:50000+0; % sec
% To show date as plot label it should be converted from numbers to letters
hr_matlab = time' + datenum('4:10:44 PM');
hr= datestr(hr_matlab, 'HH:MM:ssPM');
figure(222)
plot(hr,S,'-b','LineWidth',2)
I am using MATLAB2014a and don't have access to function datetime.
datenum converts the date to a number that represents days as whole numbers. For that reason, when you add the vector [1,2,3,...], you acturally add days to your fixed time ('4:10:44 PM').
if you want to add it as seconds, you need to divide time in the amount of seconds per day:
hr_matlab = (time')/86400 + datenum('4:10:44 PM');
One simple option is to add two date numbers:
hr_matlab = datenum('4:10:44 PM') + datenum(0, 0, 0, 0, 0, time.');

How can I find the difference in hours between 2 times in character arrays?

I have 2 times stored in character arrays in MATLAB.
a = '11:00 PM'
b = '07:30 AM'
I want to find the difference in hours between the 2 times, which should be 8.5 hours in this example. Is there any short method to do that? I can datenum both numbers, subtract them, datevec the difference, extract the hours and minutes from the vector, and convert them into hours, but this takes a lot of lines. Is there a more efficient way of doing this or is there an existing function?
You can do this by converting each string using datetime, taking the difference, then converting the result with hours:
numHours = hours(diff(datetime({a; b}, 'InputFormat', 'hh:mm a')));
numHours = numHours + 24.*(numHours < 0)
numHours =
8.5000
The second line accounts for the condition in your example, where the second time has to occur on the next day for the time difference to be positive, so 24 hours are added to the (negative) difference.
add a date to the time
like
a = '1/1/2000 11:00 PM'
b = '1/1/2000 07:30 AM'
the convert the string to datetime
x=str2num(strrep(a,':',''))
y=str2num(strrep(b,':',''))
then fine the difference between 2 dates
e = etime(x,y)
this will give you number of seconds between both times

method for converting seconds from date to datetime

Is there a method in matlab to convert seconds from a known date to a standard date time format?
For example, if I have a vector of values shown as seconds from 1901/01/01, how would I convert them to a dateTime? In this case a value of 28125 would correspond to 1981/01/01. Is there an efficient method for doing this?
The numbers in your example do not make sense so it is not clear if your time is in seconds or days but since you asked for seconds I will use this.
What you want to achieve can be done using datenum function. This function returns the number of (fractional) days from 1/1/0000. So first you need to find your offset, e.g.:
offsetInDays = datenum(1901,1,1);
Next, you convert the date from seconds to days:
dateInDays = YourRequiredDateInSec * 3600 * 24;
Finally, you date is given by
RequiredDate = datestr(offsetInDays + dateInDays);