calculating number of days between 2 days tcl - date

I am calculating the number of days between two dates(the 2 dates are in seconds). The following gives me the coorect result but it gives me a negative value.
For example -7.0. I am not sure why..
Also can I remove the decimal point and display?
set interval [expr { $start_date - $get_date }]
set days [expr { floor($interval / (60*60*24)) }]
puts "Start Date: $start_date <br>"
puts "Stop Date: $get_date <br>"
puts "Total number of dates betwen 2 days: $days"

You're subtracting the end (assuming that's what $get_date is) from the start. Think of it like numbers, where a later date is a bigger number - if you subtract a large number from a small number, you get a negative value, right?
So you probably just want to reverse the arithmetic:
set interval [expr { $get_date - $start_date }]
I've no idea about the decimal point part, I'm afraid... perhaps (based on this documentation) just:
set days [expr { int($interval / (60*60*24)) }]
EDIT: As noted in comments, some care is required when it comes to "days" between two events. Do you mean elapsed days, 24 hours per day, or "local" days? Are your input values in local time, UTC, or something else? Could you perhaps use a dedicated date/time library to handle this? (I have no idea whether tcl has such a thing, but I'd expect it to.)
You should think really carefully about exactly what behaviour you want in what situation, and write tests accordingly.

Not all days are 86400 seconds long, because of little things like daylight savings time. Because of this, you need to do some rounding in your calculation (and use floating point division):
set days [expr {round($interval / double(60*60*24))}]
You also usually subtract the start from the end when calculating the length of an interval, not the other way round. Gets the sign right.

Related

How many days in ISO8601 duration 'months' and 'years'?

I need to represent a duration of 100 days.
From Wikipedia:
Durations are represented by the format P[n]Y[n]M[n]DT[n]H[n]M[n]S
But for a duration, how many days are in a month? Surely it depends on which month we're in... Ditto, days in a year.
Following up on my comment, it looks like it's perfectly legal to specify a count larger than the number of units that make up the next "larger" unit, so you could just use P100D. Wikipedia says:
The standard does not prohibit date and time values in a duration representation from exceeding their "carry over points" except as noted below. Thus, "PT36H" could be used as well as "P1DT12H" for representing the same duration. But keep in mind that "PT36H" is not the same as "P1DT12H" when switching from or to Daylight saving time.
While the example is for hours, it seems like days should be fine too (and as your problem illustrates, even more useful, since months and years aren't fixed quantities). That said, the standard doesn't specify the maximum number of digits for each unit, only:
Leading zeros are not required, but the maximum number of digits for each element should be agreed to by the communicating parties.
So whatever is consuming your durations must accept at least 3 digits per element for P100D to work; that doesn't seem like an unusually high level of required support.

Calculating the difference between two dates using age and extract gives differing results in Postgresql

I'm using Postgresql (on Amazon Redshift), and I need to calculate the difference between two dates and then use that value in a formula to compute a ratio, so the date difference needs to be translated to a numeric value, preferably a float or double precision.
I have two dates: 1/1/2017 and 1/1/2014. I need to find the difference between these two dates in number of days.
When I use the age function I get 1080 days:
select age('2017-01-01','2014-01-01')
However, since age returns an interval and I need to work with a numeric result, I am using EXTRACT to convert the final value. I chose epoch since I wasn't able to find any other value for EXTRACT that would yield the number of time units between the two dates. This formula yields 1095.75 days (the divisor is the number of seconds in a day):
select extract(epoch from age('2017-01-01','2014-01-01'))/86400
Why am I getting a difference of 19.75 days when using age vs using extract?
Did you try
select '2017-01-01'::date - '2014-01-01'::date;
The difference between two dates is number of days in integer
1080 is the figure you would get if every month was 30 days long (36 months by 30 days equals 1080), as it would be if you used justify_days (either explicitly or if the DBMS called it implicitly). You don't say how you're getting this 1080 figure since I believe the duration would normally just print out something like 3 years, but that seems the most likely case
1095.75 seems the more correct figure, being 365.25 days multiplied by three years.
Out of those two, I would go with the latter method.
Although, as pointed out at http://www.postgresql.org/docs/8.1/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT, calculating the difference between two date types should yield the number of days:
select dtend - dtstart from somewhere
Redshift release notes say they recently released a months between function which looks similar to oracles months between function if that's what you're looking for. http://docs.aws.amazon.com/redshift/latest/dg/r_MONTHS_BETWEEN_function.html

Matlab change x axis tick label

I am relatively inexperienced with matlab, as I only use it occasionally. I am trying to plot a large range of values against time and I am running into some problems.
The data, which is from a text file, with about 55000 entries, gives the information in the following format:
year month day hour minute second value
The seconds column has accuracy of 6 decimal places and there are about 24hrs worth of data.
What I want to do is plot the values against time, which works fine. However as a result of my code below, the x-axis has label ticks in serial date number format, which is not very useful when looking at the figure. I want to change the labels to something more useful such intervals of hours. However I am not sure how to go about doing this.
Here is the code:
A = dlmread('data.txt',' ');
time = datenum(A(:,1),A(:,2),A(:,3),A(:,4),A(:,5),A(:,6));
scatter(time,A(:,7),1)
axis([min(time) max(time) min(A(:,7)) max(A(:,7))])
I found a solution here: matlab ticks with certain labels however, the process here is manual and with so much information I don't want to do this manually. How would I automate this process? or is there a better way to do what I am trying to achieve?
EDIT: I also found this method: http://www.mathworks.com/help/matlab/ref/datetick.html#btpnuk4-1, however, I dont want to show the actual date, I rather want to show intervals of time, ie an hour or 30 minutes.
EDIT 2: I have found a somewhat satisfactory solution. It could still be improved upon, so I don't know if I should submit this as an answer to my own question or not, but here it is:
A = dlmread('data.txt',' ');
time = datenum(A(:,1),A(:,2),A(:,3),A(:,4),A(:,5),A(:,6));
temp= time(1);
timediff = time - temp;
scatter(timediff,A(:,7),1)
axis([min(timediff) max(timediff) min(A(:,7)) max(A(:,7))])
datetick('x', 'HH')
This takes the original time vector in serialized time format and subtracts the first time from all the subsequent times to get the difference. The it uses the datetick function to to convert that to hours. It isn't ideal because instead of 24 hours it goes back to 00, but its the best I have tried thus far.
With reference to the other article, you will have to follow the same method but in order to automate the process you'll need to form the vectors of xtick and xticklabels as you read in the data and after you've plotted the data change the xticks and xticklabels.
Its not difficult what you're trying to do, but I will need more details of how you want to organize the ticks to be able to exactly say the steps that you'd have to follow
Matlab serial time is simply days since January 1, 0000, so your timediff variable is really elapsed days (and fractions thereof) since the start of your experiment. If you want your x ticks to be elapsed hours you could multiply timediff by 24.
scatter(timediff * 24, values)
This avoids the weirdness that can arise when using datetick as well.

How to convert month to other duration measurement types?

For some duration-related calculations I need to convert values measured in "months" to other formats, such as years, days, or hours.
For example, what is the proper way to measure a month in terms of days? is it 30 days? or 30.4375 days? (365.25 / 12) and which format would be useful in which cases?
If you have any information on the casual/business use cases for such conversions it would be helpful too.
Unfortunately, there's really no single generally valid answer to your question.
If this is for business use, first check whether there are any existing relevant standards or business practices that define what a "month" means in your business context. If yes, you should follow that definition as closely as possible, however silly or awkward it may seem.
For casual use, the simplest solution is probably to pick any widely use date manipulation library and do whatever it does. The default behavior may not be perfect, but it's probably at least close to a fairly sensible compromise of the many contradictory expectations that users of such a library may have.
OK, but what if you insist on rolling your own solution? In that case, the first choice you should make is how you want to represent date / time values. There are at least two common choices:
The first option is to store dates / times using a simple linear count of fixed time units from a given epoch, such as Julian days or Unix timestamps. This provides a simple and compact date/time representation, makes comparing timestamps and simple date/time arithmetic (like adding n seconds to a time value) easy, and ensures that any time value corresponds to a (more or less) unique and well defined point in time.
The downside, as you've noticed, is that arithmetic using "fuzzy" time units like months or years gets difficult: you can define a year as 365.25 days (or as 365.2425 days, to take into account that only 97 out of every 400 years are leap years in the Gregorian calendar) and a month as 1/12 years, but this will cause adding a year to a date-time value to also shift the time of day by (about) 6 hours, which may be unexpected.
This approach also doesn't let you easily represent "floating" time value, like times of day without a specified date and time zone. (You can sort of deal with floating time zones by doing your time math in UTC and just pretending that it's in your local time zone, but this can cause weird stuff to happen around DST changeovers.) Conversely, it can also cause difficulties if you need to represent imprecise date/time values, such as dates without a time component.
In particular, if you choose the "natural" representation, where imprecise datetimes are represented by their starting point, so that e.g. an unspecified time of day defaults to 00:00:00.0, then anything that causes the time part to be reduced by even a fraction of a second — like, say, shifting to a later time zone, or subtracting a fuzzy time unit that is not an integral number of days — will flip the date part to the previous day. For example, with this representation, subtracting one year (= 265.2425 days) from January 1, 2014 will yield a date in 2012 (specifically, December 31, 2012, 17:56:32)!
You can avoid some of these issues by representing imprecise date/time values by their midpoints instead, so that e.g. the date 2014 is treated as shorthand for June 2, 2014, 12:00:00. What you lose, with this representation, is the ability to build datetimes just by adding up components: with this representation, 2014 + 5 months + 3 days isn't anywhere near May 3, 2014.
Also, just when you think you've at least got simple non-fuzzy time arithmetic unambiguously sorted out, someone's going to tell you about leap seconds...
The alternative approach is to store datetime values in decomposed year / month / day / hour / minute / second / etc. format. With this presentation, time intervals are also naturally stored in a decomposed format: "one month + 17 days" is, in itself, a valid time interval in such a representation, and need not (and should not) be simplified further.
This has a few obvious advantages:
Fuzzy unit arithmetic is (conceptually) simple: to add one year to a date, just increment the year component by one.
Imprecise date/time values can be naturally represented: for a pure date value, the time-of-day components can simply be left undefined (= e.g. represented by negative values for the undefined components, or simply by having each datetime value store its precision).
You have precise control over when and if rollover occurs: adding a year to a date in 2014 will always yield a date in 2015.
You can also support floating time values, such as times of day without a specified date, or dates of year without a specified year. Floating time zones also become supportable.
That said, there are some disadvantages, too:
Implementing date arithmetic gets more complex, since you have to deal with non-trivial carry/borrow rules. (Quick! What's the date 10,000,000 seconds after May 3, 2014?)
You'll still have ambiguities with month arithmetic: what's the date one month after January 31? And does it depend on whether it's a leap year or not?
You can allow such a format to store "impossible" dates like "February 31", with an optional method to normalize them to, say, February 28 (or 29, for a leap year) later. This has the advantage of preserving (some) arithmetic consistency: it allows (January 31 + 1 month) + 1 month to equal March 31 as expected.
In some ways, though this merely postpones the problem: presumably, January 31 + 24 hours should fall on February 1, but what day and month should January 31 + 1 month + 24 hours fall on? The "obvious" choice would be March 1, but whatever you choose, there will be some sequence of arithmetic operations that will yield inconsistent results.

How to find out how many (if any) weekends occur in a given period

I have two numbers; dates in Unix Epoch format.
Say I have two Unix Epoch timestamps:
1349422200 = 05/10/2012 08:30
1350489600 = 17/10/2012 17:00
I am able to find out how many days are between the two date/times, no problem.
What I would like to be able to work out is how many of those days are Saturdays or Sundays (Non-Weekdays). I'm sure there has to be an easy way to go about this but I can't for the life of me figure it out without doing a load of for() loops.
Any help greatly appreciated.
Be more specific with your definition of weekend. Do you only want to include whole weekends (the entire 48 hour period of saturday and sunday)? Or does any range of time containing midnight on Friday night/Saturday morning count as a weekend? Do half weekends count as half, or do you round to the nearest whole number?
In any case:
Figure out what comprises a weekend
Find the first and last weekends in your range of time
Find the time difference between them, in days, and divide by 7
Edit: you're seeking the exact amount of weekend time, with no rounding.
First, split the timespan into 3 chunks:
Everything from the beginning of the range up until the first possible Monday morning at midnight
Everything from the end of the previous block up to the last possible Monday morning at midnight
Everything from the end of the previous block to the end of the range
Then calculate the amount of weekend in each block, and sum them up.
The first block will contain no weekend time if it has a length of zero. If it has a length of 48 hours or less, its weekend time will equal its length. Otherwise, its weekend time will be 48 hours.
The middle block's weekend time is its duration multiplied by 2/7 (trivial, since by our restrictions on its start and end, it is a whole number of weeks.)
The final block will contain no weekend time if its duration is less than or equal to five days. If its duration is greater than five days, its weekend time will equal its duration minus five days.
Special cases
If the block contains no monday midnights, consider the second and third blocks to have a length of zero. Find the beginning and the end of the one weekend inside the block (if it exists) and calculate the overlap.
If the block contains exactly one monday midnight, consider the first block the time before it, the second block to be of zero length, and the third block the time after it, and calculate as usual.
I'm sure there are some much faster and less-processor hungry methods to getting around this. But for me this method was good enough and gets the job done.
//$sDateRaw = First day at 00:00 in Unix Epoch
//$eDateRaw = Last day(+1) at 00:00 in Unix Epoch
//86400 = Number of seconds in 1 day
for($i=$sDateRaw;$i<$eDateRaw; $i+=86400){
if(date("N",$i) != 6 && date("N",$i) != 7){
$weekDays += 1;
}
}
//$weekDays = Total number of days excluding weekends