Unix gettimeofday() - compatible algorithm for determining week within month? - date

If I've got a time_t value from gettimeofday() or compatible in a Unix environment (e.g., Linux, BSD), is there a compact algorithm available that would be able to tell me the corresponding week number within the month?
Ideally the return value would work in similar to the way %W behaves in strftime() , except giving the week within the month rather than the week within the year.
I think Java has a W formatting token that does something more or less like what I'm asking.
[Everything below written after answers were posted by David Nehme, Branan, and Sparr.]
I realized that to return this result in a similar way to %W, we want to count the number of Mondays that have occurred in the month so far. If that number is zero, then 0 should be returned.
Thanks to David Nehme and Branan in particular for their solutions which started things on the right track. The bit of code returning [using Branan's variable names] ((ts->mday - 1) / 7) tells the number of complete weeks that have occurred before the current day.
However, if we're counting the number of Mondays that have occurred so far, then we want to count the number of integral weeks, including today, then consider if the fractional week left over also contains any Mondays.
To figure out whether the fractional week left after taking out the whole weeks contains a Monday, we need to consider ts->mday % 7 and compare it to the day of the week, ts->wday. This is easy to see if you write out the combinations, but if we insure the day is not Sunday (wday > 0), then anytime ts->wday <= (ts->mday % 7) we need to increment the count of Mondays by 1. This comes from considering the number of days since the start of the month, and whether, based on the current day of the week within the the first fractional week, the fractional week contains a Monday.
So I would rewrite Branan's return statement as follows:
return (ts->tm_mday / 7) + ((ts->tm_wday > 0) && (ts->tm_wday <= (ts->tm_mday % 7)));

If you define the first week to be days 1-7 of the month, the second week days 8-14, ... then the following code will work.
int week_of_month( const time_t *my_time)
{
struct tm *timeinfo;
timeinfo =localtime(my_time);
return 1 + (timeinfo->tm_mday-1) / 7;
}

Assuming your first week is week 1:
int getWeekOfMonth()
{
time_t my_time;
struct tm *ts;
my_time = time(NULL);
ts = localtime(&my_time);
return ((ts->tm_mday -1) / 7) + 1;
}
For 0-index, drop the +1 in the return statement.

Consider this pseudo-code, since I am writing it in mostly C syntax but pretending I can borrow functionality from other languages (string->int assignment, string->time conversion). Adapt or expand for your language of choice.
int week_num_in_month(time_t timestamp) {
int first_weekday_of_month, day_of_month;
day_of_month = strftime(timestamp,"%d");
first_weekday_of_month = strftime(timefstr(strftime(timestamp,"%d/%m/01")),"%w");
return (day_of_month + first_weekday_of_month - 1 ) / 7 + 1;
}
Obviously I am assuming that you want to handle weeks of the month the way the standard time functions handle weeks of the year, as opposed to just days 1-7, 8-13, etc.

Related

Pine scripting: how to find the price X days ago

In Pine Script, how do I find the price based on a certain number of days ago? I've tried something like this...
// Find the price 90 days ago
target = time - 90 * 60 * 60 * 24 * 1000
valuewhen(time < target, close, 1)
...however time < target never seems to return true – presumably because the current bar's time cannot also be in the past at the same time. Perhaps valuewhen() wasn't designed to be used with dynamic values that change on every bar?
Do I need to use a loop instead, and scan through every past bar until I find the date I'm looking for?
Perhaps there's a better way, but the workaround I'm using currently using is a function with a for loop, scanning backwards until the appropriate date is found. Here is my function:
priceXDaysAgo(numDays) =>
targetTimestamp = time - numDays*60*60*24*1000
// Declare a result variable with a "void" value
float result = if false
1
// We'll scan backwards through the preceding bars to find the first bar
// earlier than X days ago (it might be a little greater than X days if
// there was a break in trading: weekend, public holiday, etc.)
for i = 1 to 1000
if time[i] < targetTimestamp
result := close[i]
break
result
You can then call the function anywhere in your script:
priceXDaysAgo(90)

Codename One days left in current week or month

I am building a calendar application that needs to calculate the remaining days of (1) the current week and (2) the current month.
What I have tried was using the java.util.Calendar API, but it seems not to be fully supported.
int days = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
How would I do this in CN1?
Many thanks in advance.
We would love to add support for JSR310 in the future which would probably solve this in a more elegant way. This is something that can be done as a cn1lib without modifying Codename One but would require some work...
A bit of a hack to do this is:
int month = cal.get(Calendar.MONTH);
cal.set(Calendar.DAY_OF_MONTH, 1);
if(month == cal.DECEMBER) {
cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) + 1);
cal.set(Calendar.MONTH, Calendar.JANUARY);
} else {
cal.set(Calendar.MONTH, month + 1);
}
int day = 24 * 60 * 60000;
cal.setTime(new Date(cal.getTime().getTime() - day));
I don't know CN1, but you can calculate the values using a subtraction between the max and the current value:
(1) cal.getActualMaximum(Calendar.DAY_OF_WEEK) - cal.get(Calendar.DAY_OF_WEEK)
(2) cal.getActualMaximum(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH)
For your notification: The first day of the week is sunday in the api of calendar. When your week should start with monday you have to reduce the offset by 1.

java.time.Instant.plus(long amountToAdd, TemporalUnit unit) Unsupported unit

I trying to add few years to current time. My code looks like:
// ten yeas ago
int backYears = 10;
Instant instant = ChronoUnit.YEARS.addTo(Instant.now(), -backYears);
But I got an exception:
java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Years
at java.time.Instant.plus(Instant.java:862)
When I opened the method Instant.plus I see the following:
#Override
public Instant plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
switch ((ChronoUnit) unit) {
case NANOS: return plusNanos(amountToAdd);
case MICROS: return plus(amountToAdd / 1000_000, (amountToAdd % 1000_000) * 1000);
case MILLIS: return plusMillis(amountToAdd);
case SECONDS: return plusSeconds(amountToAdd);
case MINUTES: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_MINUTE));
case HOURS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_HOUR));
case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2));
case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY));
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.addTo(this, amountToAdd);
}
As you can see MONTHS and YEARS are unsupported. But why?
With an old java.util.Calendar I can do that easily:
Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(Calendar.YEAR, amount);
return c.getTime();
The only one reason what I guess is that we don't know how many days in a month and year because of leap day 29 Feb.
But to be honest we also have a leap second.
Thus I think that this is a bug and all ChronoUnits should be supported.
The only one question is: do we need to take in account leap second and leap day.
As for my needs it's okay just to assume that month has 30 days and year 365.
I don't need to make something like Calendar.roll() but this can satisfy me too.
Let’s try something out. I am taking an instant as ZonedDateTime and subtracting 10 years in different time zones.
OffsetDateTime origin = OffsetDateTime.of(2018, 3, 1, 0, 0, 0, 0, ZoneOffset.UTC);
Instant originInstant = origin.toInstant();
Instant tenYearsBackKyiv = origin.atZoneSameInstant(ZoneId.of("Europe/Kiev"))
.minusYears(10)
.toInstant();
long hoursSubtractedKyiv = ChronoUnit.HOURS.between(tenYearsBackKyiv, originInstant);
System.out.println("Hours subtracted in Київ: " + hoursSubtractedKyiv);
Instant tenYearsBackSaoPaulo = origin.atZoneSameInstant(ZoneId.of("America/Sao_Paulo"))
.minusYears(10)
.toInstant();
long hoursSubtractedSaoPaulo = ChronoUnit.HOURS.between(tenYearsBackSaoPaulo, originInstant);
System.out.println("Hours subtracted in São Paulo: " + hoursSubtractedSaoPaulo);
The output is:
Hours subtracted in Київ: 87648
Hours subtracted in São Paulo: 87672
As you can see, 24 hours more (1 day more) is subtracted in São Paulo compared to Київ (Kyiv, Kiev). You may already have figured out that it’s because there we pass from 1 March to 29 February three times in leap years, in Київ only twice.
The old and now outdated Calendar class always had a time zone in it, so knew in which time zone to subtract years (another thing is it was happy to give you a result even in situations where it was unclear which result you wanted). The modern classes ZonedDateTime, OffsetDateTime and LocalDateTime can do the same. So use them. An Instant conceptually doesn’t have a time zone, so refuses to do operations that depend on time zone (I know it’s implemented using UTC, but we should regard this as an irrelevant implementation detail, not as a part of the specification of the interface to the class).
Neither the old nor the modern classes take leap seoncds into account, and you are right, only therefore can an Instant add and subtract days, hours and minutes.

how to check if a number is whole number or contains a decimal

If a number is 2017 and I divide it by 4, I get 504.25.
if the number is 2016 an I divide it by 4, I get 504.
My question is, is there a way to use perl to check if a number that was divided, if the answer is a whole number and has NO decimal at all?
UPDATE: I got it working from the answer I selected below. I was trying to check if this is leap year, because today my code broke, because my code ran from the cron job as set to run on the last day of every month. Typically for feb, that is the 28th, so it ran on the 28th and shut the website done for the end of month maintenance. so what I have it do now is run on both Feb 28th and Feb 29th (For if there is a 29th) and in the code, I have it check if it is leap year now like this:
my $_leapNum = 4; # Leap year is always divisible by 4 with no remainder...
my $_NotLeapRemain = $_lTimeYYYY % $_leapNum; # I have $_lTimeYYYY built for the year only - longyear
if($_NotLeapRemain) {
my $_isLeapYear = 0;
} else {
my $_isLeapYear = 1;
}
Then later I check if it is leap year. If it is, then I check if the day is 28th, if it is, then it just exits. If it is the 29th, then it does what it was intended to do.
I tested it and it works perfectly now.
Thank you for your help.
-Rich
If you want to know if the result of dividing a $dividend by a $divisor is going to be a whole number or a number with a fractional portion, you can test that condition first:
if (my $remainder = $dividend % $divisor) {
print "$dividend cannot be divided evenly by $divisor.",
" There is a remainder of $remainder.\n";
}
else {
print "$dividend is evenly divisible by $divisor,",
" and the result is ", $divident / $divisor, "\n";
}
*EDIT: * This answer was posted in response to the original, un-edited question, which asked how to determine if the result of division contains a decimal portion. Now that the sense of the question changed toward date math, I agree that a DateTime solution is much better.

Convert unix time to month number?

Using os.time how can I get how many months have passed since the unix epoch (Unix Timestamp)
I just need it for a month ID, so any kind of number would be fine, as long as it changes every month, and it can be reversed to get the actual month.
local function GetMonth(seconds)
local dayduration,year = 3600*24
local days={31,0,31,30,31,30,31,31,30,31,30,31}
for i=1970,10000 do -- For some reason too lazy to use while
local yeardays = i%4 == 0 and i%100 ~= 0 and 366 or 365
local yearduration = dayduration * yeardays
if yearduration < seconds then
seconds = seconds - yearduration
else
year = i break
end
end
days[2]=(year%4==0) and 29 or 28
seconds = seconds%(365*24*3600)
for i=1,12 do
if seconds>days[i]*dayduration then
seconds=seconds-days[i]*dayduration
else
return --i + year*12 <-- If you want a unique ID
end
end
end
Currently, it'll give the number 2, since it's February. If you uncomment the code at the end for the unique ID, you'll get 554 instead, meaning we're currently at the 554th month since the epoch.
As Jean-Baptiste Yunès said in his answer's comments, I'm not sure if your sentence:
NOTE: This is for Lua, but I'm unable to use os.date
meant you have no os.date, or that you don't know how to use it. You have an answer for both cases, you can use the one you need.
This may do the trick:
print (os.date("*t",os.time())["month"])
os.time() gives you the current date as a number. os.date("*t",...) converts it into a table in which the month equals to the number of the month corresponding to the date.