What do the correct arguments for Date dayMonthYearDo: look like in Smalltalk (Pharo / Squeak) - date

Date dayMonthYearDo: aBlock
"Supply integers for day, month and year to aBlock and return the result"
^ start dayMonthYearDo: aBlock
What should a typical valid block look like for this message?

In this case the comment "Supply integers, etc." means that the argument aBlock will receive three integers as "actual" arguments: day number, month index and year. This means that you will have to create a block with three "formal" arguments, say, day, monthIndex and year as in:
aDate dayMonthYearDo: [:day :monthIndex :year | <your code here>]
The code you write inside <your code here> can refer to the "formal" parameters day, monthIndex and year, much as if it was a method with these three arguments.
This is how blocks generally work in Smalltalk.
Example
aDate
dayMonthYearDo: [:day :monthIndex :year |
monthIndex + day = 2
ifTrue: [Transcript show: 'Happy ' , year asString, '!']]
UPDATE
The example above checks for January 1st by "ingeniously" comparing monthIndex + day with 2. In fact, since both variables are >= 1 the only way to get 2 is when day and monthIndex are both 1, i.e., when the receiver aDate is January 1. A more "serious" approach would look like
(monthIndex = 1 and: [day = 1]) ifTrue: [ <etc> ]

Something like this:
Date today dayMonthYearDo: [:d :m :y| Transcript cr;
show: 'today is the ';
show: d;
show: 'th'
]
today is the 28th
But of course you may do different things that just showing things on transcript

Related

Trouble with a multiple condition when statement in CoffeeScript

In Finland, like in many countries, we have name days for different names.
I'm trying to write an Ubersicht app to display the day of the year, and the name of that day.
I've brought in the Day of the Year (%j) and Year (%Y), split them so I can manipulate them, and have found a way to find a leap year in CoffeeScript.
However, because leap years have an extra day, the 29th Feb is not a name day (along with 1st Jan and 25th Dec), so I want to display "No names today!" on those days, both when it is, and isn't, a leap year.
command: "date +%j,%Y"
update: (output) ->
dateString = output.split(',')
yearday = parseInt(dateString[0])
year = dateString[1]
leapyear = (year % 400 == 0) or (year % 4 == 0 && year % 100 != 0)
# The Switch statement
yearday = switch
when (leapyear and yearday is [1, 60, 360]) then "No names today!"
else
when yearday is 2 then " Aapeli "
when yearday is 3 then " Elmer, Elmo "
when yearday is 4 then " Ruut "
... and so on
The problem I'm having is that I'm getting an ParseError: 'unexpected when'.
I'm pretty new to building widgets (I have an idea how I would do this in Python), and I'm having some difficulty with my switch statement.
I have also tried bringing in the month day (%d) and month number (%e), but I ran into similar issues there (multiple when conditions e.g. when month = 3 and day = 5 (for 5th May) not working).
Any help would be greatly appreciated. As I said, I'm new to CoffeeScript, so explanations would be greatly appreciated as well.
You might want to reread switch syntax
yearday = switch leapyear
when 2 then 'Aapeli'
when 3
if additional_conditionals then A else B
when 4 then 'Ruut'
else 'No names today!'
# else is default, you can't nest additional when statements here
However, the simpler solution would be to use an array instead.
(This is not quite about Coffeescript but applies to thinking about programming in general.)
dayNames = ['', '', 'Aapeli', 'Elmer, Elmo', 'Ruut']
dayName = (day) => switch day
when 0 then 'fails, no 0th day' # optional
when 1, 60, 360 then 'No names today!'
else "Name of day #{day} is #{dayNames[day]}."
# Additionally, don't prewrite the spaces.
# Use string manipulation like above instead
# (note the difference between single and double quotes)
console.log dayName 4
# 'Name of day 4 is Ruut.'
console.log dayName 60
# 'No names today!'
(Btw please remove extra info about Finland days, it's just irrelevant..)
Cheers :)

How to get the first business day in a new month after the weekend?

How can I in a smart way get the first business day of a month after the weekend?
To get the first business day of the month (given dateInput), we can do:
firstBusdayMonth = fbusdate(year(dateInput),month(dateInput));
As an example, for November, using the above function will return Thursday November 1 as the first business day. However, the first business day of the month after the first weekend is Monday November 5. How can I get this latter date?
Notes:
The weekend does not have to be in the same month.
If the Monday is not a working day, then I would like it to return the next business day
This function will do the trick. Here is the logic:
Create a datetime array for all days in the given month.
Get the day numbers.
Create a logical array, true from the first Monday onwards (so after the first weekend, accounting for the last day of the previous month being a Sunday).
Create another logical array using isbusday to exclude Mondays which aren't working days.
Finding the first day number where these two logical arrays are true, therefore the first business day after the weekend.
Code:
function d = fbusdateAferWE( y, m )
% Inputs: y = year, m = month
% Outputs: day of the month, first business day after weekend
% Create array of days for the given month
dates = datetime( y, m, 1 ):days(1):datetime( y, m, eomday( y, m ) );
% Get the weekday numbers to find first Monday, 1 = Sunday
dayNum = weekday( dates );
% Create the logical array to determine days from first Monday
afterFirstWeekend = ( cumsum(dayNum==2) > 0 ).';
% Get first day which is afterFirstWeekend and a business day.
d = find( afterFirstWeekend & isbusday( dates ), 1 );
end
You could probably speed this up (although it will be pretty rapid already) by not looking at the whole month, but say just 2 weeks. I used eomday to get the last day of the month, which means I don't have to make assumptions about a low number of holiday days in the first week or anything.
Edit: Working with datenum speeds it up by half (C/O JohnAndrews):
function d = fbusdateAferWE( y, m )
% Inputs: y = year, m = month
% Outputs: day of the month, first business day after weekend
% Create array of days for (first 2 weeks of) the given month
dates = datenum(datetime(y,m,1)):datenum(datetime(y,m,eomday(y,m)))-14;
% Get the weekday numbers to find first Monday, 1 = Sunday
dayNum = weekday( dates );
% Create the logical array to determine days from first Monday
afterFirstWeekend = ( cumsum(dayNum==2) > 0 ).';
% Get first day which is afterFirstWeekend and a business day.
d = find( afterFirstWeekend & isbusday( dates ), 1 );
end
I would add something like this after your statement:
[DayNumber, DayName] = weekday(firstBusdayMonth);
if DayNumber > 2
day = 10 - DayNumber;
else
This works because 'weekday' will return a number between 1 (Sunday) and 7 (Saturday).
The fbusdate() function will never return a 1 or 7, so we can ignore those cases.
If weekday(fbusdate()) == 2, the first is on a Monday and the firstBusdayMonth variable doesn't need to be changed.
If weekday(firstBusdayMonth) returns between 2 and 6, we need to skip to the next week, so we subtract the weekday value from 10 to find the next Monday.
It might not be the most elegant solution, but should work.

Dates from the last month of specific ranges

How can I extract data from the previous month into three sections? I can use the function LASTMONTH but that gives me the whole month.
I need it split into three sections:
1st - 10th of last month
11th - 20th of last month
21st to end of last month
Sounds like a two step problem:
Write a formula which comes up with 3 values based on date
Group and Sort your data based on that formula
The formula in question will look something like the following:
IF {yourDate} in date(year(currentdate),month(currentdate)-1, 1) to date(year(currentdate),month(currentdate)-1, 10)
THEN "A"
ELSE IF {yourDate} in date(year(currentdate),month(currentdate)-1, 11) to date(year(currentdate),month(currentdate)-1, 20)
THEN "B"
ELSE IF {yourDate} in date(year(currentdate),month(currentdate)-1, 21) to date(year(currentdate),month(currentdate),1)-1
THEN "C"
ELSE "D"
Where A, B, and C are valid dates and D is all the invalid ones. Substitute as appropriate.

How to check/calculate the week-day count (using Date functions) using Javascript?

I would like to check if a given date is the first, second, third, fourth or last monday, tuesday, wednesday,..., sunday in the dates month.
The function should look like this:
if(checkdate(date, "second", "monday"))
{
alert("This is the second monday of the month");
}
else
{
alert("This is NOT the second monday of the month");
}
I would rather write a function that returns an object telling me the day and the week-number-in-month of the given date. Something like:
function infoDate(date) {
return {
day: date.getDay()+1,
week: (date.getDate()-1)%7+1
}
}
Then I can read the returned object and find out if it's the second monday or whatever:
var info = infoDate(date);
if(info.day==1 && info.week==2) {
// second monday
}
Of course, you can still write another localized function that does exactly what you ask for based on an array of numeral and day names.
use getDate() to get day of the month
then getDay() to get the day of the week
using these two you should be able to accomplish your task. Refer to this http://www.w3schools.com/jsref/jsref_obj_date.asp
It seems to me you only need to divide the date by 7 to know how many full weeks have passed, no matter what day it is. Subtracting one before dividing and adding it after sets the first week from 0 to one.
Date.prototype.weekofMonth= function(){
return Math.floor((this.getDate()-1)/7)+1;
}
alert(new Date().weekofMonth())

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

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.