How to get N days ago in Dart's DateTime? - dart

There's the subtract() method but the documentation says it's not aware of daylight savings which makes it pretty much useless in this case, or in any other case except where the programmer doesn't know how many milliseconds there are in 24 hours.
I'm thinking of two ways:
get the day of the month, and then subtract N from it and if it's less than 1 then subtract the month and the year if appropriate and set the day for the last day of whichever month it turns out to be
OR
subtract N days from the noon of the current day and then get start of the day for the resulting day
Is there some easier/better way to do this?

You should probably try to convert both DateTimes to UTC (standardize), then call difference(). That converts it to a nice, easy Duration, which you can convert as necessary to hours, days, months, or whatever else.
DateTime one = somedatetime.toUtc();
DateTime two = someotherdatetime.toUtc();
Duration diff = one.difference(two);
//Then just convert...
return diff.inDays;

Related

How to convert Server Date format in hour or day?

How I will change this date format to in a day or hours
"modifiedTime": "2021-01-30T12:15:14.896Z[GMT]",
"modifiedTime": "2021-01-29T13:58:37.328Z[Etc/UCT]",
DateTime.parse(aString) should handle a Z suffix for timezone or an explicit offset (-05:00). To parse other named timezones, you'll need the https://pub.dev/packages/timezone package, which unfortunately has to get updated at least a few times a year because politicians keep messing with things like DST.

Ruby convert decimal duration (day|week|month|year) to end date

I have a start_at, a decimal quantity and an interval which is one of day | week | month | year.
start_at = Time.parse('2016-01-01 00:00:00 UTC') # leap year
quantity = BigDecimal.new('1.998') # changed from 2.998, should end on 2/29/16 sometime
interval = 'month' # could be any of day|week|month|year
With whole numbers, I've used duration i.e. 1.month, and I looked at Date#advance, though it only recognizes integer values.
It would seem simple but I cannot find anything in the standard libraries or in ActiveSupport.
References:
SO answer potentially used for input to Date#advance?
SO explanation of duration
Question
How can I establish the end_at date from a decimal?
Why? What purpose?
Proration to the second for a given amount and given interval.
Expectations
I'm looking for an end_at to the second as accurate as possible with respect to advancing the next interval(s) by the decimal quantity. Given interval = 'month', for the fractional part, when you pass the start of the month, means you are in that month and using it's duration. For example, January 2016 is 31 days, while February (leap) is 29 days (only in the leap year).
I'd say your best option is to use Ruby's date methods to advance time based on the whole number of the decimal, then calculate how many seconds your fraction is of your current interval.
So for 1.998 months, advance time 1 month. Find the current month you are in and get the .998 of the seconds in that month (i.e. for July, 31x24x60x60x.998) and then advance time that many seconds.
What does advancing time a fractional month mean?
Lets say we have the following date 2015-01-01 00:00:00 UTC. It is easy to advance exactly 1 whole month, we simply increment the number that represents months: 2015-02-01 00:00:00 UTC. Alternatively, we could view this as adding 31 days, which we know is the number of days in January.
But what if we want to advance 0.5 months from 2015-01-01 00:00:00 UTC?
We can't just increment like we did when advancing a whole month. Since we know January has 31 days, perhaps we could just advance 15.5 days: 2015-01-16 12:00:00 UTC. That sort of works.
How about 1.5 months from 2015-01-01 00:00:00 UTC? If we combine our previous approaches, we'd first increment, getting us to 0.5 left to advance and 2015-02-01 00:00:00 UTC. Then we'd take half of 28 and get to 2015-02-15 00:00:00 UTC.
But wait, what if instead we took the total number of days between the two months and then took 3/4 of that? Like 2(month) * (3/4), which would simplify to (3(month)) / 2, or 1.5(month). Lets try it.
(28 days + 31 days) * 0.75 = 44.25 days
Now adding that to 2015-01-01 00:00:00 UTC we get 2015-02-14 06:00:00 UTC. That's three-quarters of a day off from our other answer.
The problem here is that the length of a month varies. So fractional months are not consistently definable.
Imagine you have two oranges. One contains a little bit more juice than the other (perhaps 31ml and 29ml of juice). Your recipe calls for the juice of 1.5 oranges. Depending on which one you decide to cut in half, you could have either 44.5 ml or 45.5 ml. But if your recipe calls for 40 ml of orange juice, you can pretty consistently measure that. Much like you can consistently (kind of) increment a date by 40 days.
Time is really tricky. We have leap seconds, leap years, inconsistent units (months), timezones, daylight saving time, etc... to take into account. Depending on your use case, you could attempt to approximate fractional months, but I'd highly recommend trying to avoid the need for dealing with fractional months.

week_field gives wrong week after serialization and deserialization

I'm using the week_field helper to generate a week picker in a form. When I choose a week and submit, my controller gets the correct serialized week (e.g. '2014-W03') which I can turn into a date object. That all works, but when the date is serialized again it is always decremented by 1 (e.g. it'll be '2014-W02'). I looked at the source code for the week_field helper and it serializes as
def format_date(value)
value.try(:strftime, "%Y-W%W")
end
but this doesn't seem to be the encoding when the date is parsed. Furthermore, parsing and then serializing a date yeilded this wonky result:
irb > Date.parse('2014-W03').strftime('%Y-W%W')
=> "2014-W02"
Any ideas as to what's going on here or how I can do this in a way that makes sense? I'd hate to have an extra +1 on the week number or change the week_field format_date definition if there's a cleaner route.
This is from http://apidock.com/ruby/DateTime/strftime :
%W - Week number of the year. The week starts with Monday. (00..53)
It seems you have the good old - start with 0 or start with 1 - problem. Strftime will start counting weeks with 0.
But maybe %V is the right thing for you:
ISO 8601 week-based year and week number:
The week 1 of YYYY starts with a Monday and includes YYYY-01-04.
The days in the year before the first week are in the last week of
the previous year.
%G - The week-based year
%g - The last 2 digits of the week-based year (00..99)
%V - Week number of the week-based year (01..53)

Convert week number to date range with Saturday as beginning_of_week

I need to use Saturday as the week start and calculate the beginning and the end of week from week numbers. I need week 53 to be properly accounted for as well.
Date.beginning_of_week = :saturday
works fine, but I have not found a way to generate week start and end dates only from a year and week number. Date.commercial is the only method I have been able to use thus far to convert a week number and year only to a date. I have been unable to get Date.commercial to recognize Saturdays as the week start.
I need to use Saturday as the week start and calculate the beginning and the end of week from week numbers.
Given an instance of Date representing the first Saturday, and the week number, this is quite simple, unless I'm missing something.
def beginning_of_week(first_saturday, week_num) {
return first_saturday + (7 * week_num.to_i).days
}
The days method comes from activesupport.

Calculating how many 'Midnights' is one date past another in PHP?

I have a start/end times for a calculation I'm trying to do and am having a problem seeing if the end time is before 12AM the day after the start time. Also, I need to calculate how many days past the start time it is.
What I have: Start Date, End Date
What I need:
- How many 'Midnights' is the End Date past the Start Date?
Has anyone done anything like this?
This uses PHP 5.3, if you have an earlier version you may need to use unix timestamps to figure out the difference. The number of midnights should be the number of days difference assuming both start and end times have the same time. So setting both to be midnight of their current day setTime(0,0), should make the calculation correct.
Using the DateTime objects.
$start = new DateTime('2011-03-07 12:23:45');
$end = new DateTime('2011-03-08 1:23:45');
$start->setTime(0,0);
$end->setTime(0,0);
$midnights = $start->diff($end)->days;
Without using the setTime() calls, this would result in 0, because there is less than 24 hours between start and end. With the setTime() this results in 1 because now the difference is exactly 24 hours.
The diff() function was introduced in 5.3 along with the DateInterval class. In 5.2 you can still use the DateTime class but will have to work out the total days using the Unix timestamp.
$midnights = ($end->format('U') - $start->format('U')) / 86400
You can wrap that in an abs() function to the order of start/end does not matter.
Note: These functions may need to be tested for cases that involve DST.
A comment in the php date documentation uses round after dividing by 86400 (number of seconds in a day), to counter any issues that could be involved with DST.
An alternative approach with DateTimes would be to create them in the UTC.
$utcTimezone = new DateTimeZone('UTC');
$start = new DateTime('2011-03-07 12:23:45', $utcTimezone);
$end = new DateTime('2011-03-08 1:23:45', $utcTimezone);

Resources