I am new to SML and I have write a program that takes two years and compares them, then takes two months and compares them, and finally two dates.
The problem im having is that if the year is older than the first it should stop and false, but some how not sure if it is my logic or something it continues to check the months and then the dates before returning true or false.
I want it only check the month if the year is false and only check the day if the month is false.
fun is_older(year1 : int, month1 : int, day1 : int, year2 : int, month2 : int, day2 : int) =
if year1 < year2 andalso year1 > 0
then true
else
if month1 < month2 andalso month1 > 0 andalso month2 <= 12
then true
else
if day1 < day2 andalso day1 > 0 andalso day2 <= 31
then true
else false;
I'm assuming you're trying to compare two dates in a year, and return true/false value. What you did is mostly correct. In your second if statement, you want to check if month1<month2 only if year1=year2. Otherwise,even if year1=2014, and year2=2013, you'll get true value if their month agree with your second if statement.
Similarly, in your third if statement, you want to check days only if year1=year2 andalso month1=month2.
Related
I tried in several ways to develop the condition to delete values equal to and greater than 1 and equal to and less than 15 in the "BD" column of my excel spreadsheet but this programming is not accepted. I believe it is a problem fo wrong syntax.
Dim W As Worksheet
Dim linha As Long
Dim Ultima_Linha As Long
Set W = Sheets("CONOB")
Ultima_Linha = W.UsedRange.Rows.Count
Call transformadataemdia
With W
For linha = Ultima_Linha To 2 Step -1
If Cells(linha, "j") = "4" Then
.Rows(linha).Delete
End If
If Cells(linha, "BD").Value(<=1 and >= 15) Then
.Rows(linha).Delete
End If
Next linha
End With
I expected to delete rows in column "BD" with values equal to and greater than 1 and equal to and less than 15 in the "BD" column of my excel spreadsheet but this programming is not accepted. I believe it is a problem
Hi in powerbi I am trying to create a list of dates starting from a column in my table [COD], and then ending on a set date. Right now this is just looping through 60 months from the column start date [COD]. Can i specify an ending variable for it loop until?
List.Transform({0..60}, (x) =>
Date.AddMonths(
(Date.StartOfMonth([COD])), x))
Assuming
start=Date.StartOfMonth([COD]),
end = #date(2020,4,30),
One way is to add column, custom column with formula
= { Number.From(start) .. Number.From(end) }
then expand and convert to date format
or you could generate a list with List.Dates instead, and expand that
= List.Dates(start, Number.From(end) - Number.From(start)+1, #duration(1, 0, 0, 0))
Assuming you want start of month dates through June 2023. In the example below, I have 2023 and 6 hard coded, but this could easily come from a parameter Date.Year(DateParameter) or or column Date.Month([EndDate]).
Get the count of months with this:
12 * (2023 - Date.Year([COD]) )
+ (6 - Date.Month([COD]) )
+ 1
Then just use this column in your formula:
List.Transform({0..[Month count]-1}, (x) =>
Date.AddMonths(Date.StartOfMonth([COD]), x)
)
You could also combine it all into one harder to read formula:
List.Transform(
{0..
(12 * ( Date.Year(DateParameter) - Date.Year([COD]) )
+ ( Date.Month(DateParameter) - Date.Month([COD]) )
)
}, (x) => Date.AddMonths(Date.StartOfMonth([COD]), x)
)
If there is a chance that COD could be after the End Date, you would want to include error checking the the Month count formula.
Generate list:
let
Start = Date1
, End = Date2
, Mos = ElapsedMonths(End, Start) + 1
, Dates = List.Transform(List.Numbers(0,Mos), each Date.AddMonths(Start, _))
in
Dates
ElapsedMonths(D1, D2) function def:
(D1 as date, D2 as date) =>
let
DStart = if D1 < D2 then D1 else D2
, DEnd = if D1 < D2 then D2 else D1
, Elapsed = (12*(Date.Year(DEnd)-Date.Year(DStart))+(Date.Month(DEnd)-Date.Month(DStart)))
in
Elapsed
Of course, you can create a function rather than hard code startdate and enddate:
(StartDate as date, optional EndDate as date, optional Months as number)=>
let
Mos = if EndDate = null
then (if Months = null
then error Error.Record("Missing Parameter", "Specify either [EndDate] or [Months]", "Both are null")
else Months
)
else ElapsedMonths(StartDate, EndDate) + 1
, Dates = List.Transform(List.Numbers(0, Mos), each Date.AddMonths(StartDate, _))
in
Dates
As an exercise in class, we are supposed to calculate the entry price for people in a night club, provided their age and gender. The under 25 get 20% off, and Females/NBs get 50% off, stacking multiplicatively.
While my code works, it repeats the gender check twice, which is poor form and could cause problems in a more complex application. How can I spare the repetition ?
(* OCaml Version *)
let entry_price age gender =
if age < 18
then (failwith "Must be over 18 to enter")
else let price = 12.0 in
if age <= 25
then let price = (price *. 0.8) in
if gender == 'f' || gender == 'x'
then (price *. 0.5)
else prix
else if gender == 'f' || gender == 'x'
then (price *. 0.5)
else price;;
Here is a Python version that does not repeat itself, thanks to ternary operators : (Could also be done with non-nested ifs, which Ocaml disallows)
# Python version
def entry_price(age : int, gender : str):
if age < 18:
raise ArgumentError("Must be over 18 to enter")
return (
12.0
*(0.8 if (age<25) else 1)
*(0.5 if gender in ['f', 'x'] else 1)
)
You can pretty much copy the python version:
let entry_price age gender =
if age < 18
then failwith "Must be over 18 to enter"
else
12.0
*. (if age < 25 then 0.8 else 1.0)
*. (if gender = 'f' || gender = 'x' then 0.5 else 1.0);;
There's only a slight difference in the if expression syntax, and you need to use the float-specific multiplication operator, *., instead of the int-specific *.
Also, to pick a nit, there are no statements in OCaml. Statements are an imperative/procedural construct, ie. do this, then do that. OCaml is an expression-based language, where each expression evaluates to a value. You can still discard the value of an expression, and thereby make it look like a statement, but the compiler will complain unless you are very explicit about discarding it since that is usually a user error.
#glennsl provides a nice direct translation of the Python code to OCaml, but there are other ways we can approach this.
If we create a variant type to describe ages, we can write a categorize_age function which will translate a numeric age to a descriptive term we can pattern match on. It also gives us a convenient place in the future to change what ages we use to make these determinations.
Then we can use a match on both age and gender to consider the four possible outcomes:
Under 18
Under 25 and either 'f' or 'x' gender
25 or older and either 'f' or 'x' gender
Anyone else 18 or older
type age_cat = Under_age | Legal | Adult
let categorize_age a =
if a < 18 then Under_age
else if a <= 25 then Legal
else Adult
let entry_price age gender =
let price = 12.0 in
match categorize_age age, gender with
| Under_age, _ -> failwith "Must be over 18 to enter"
| Legal, ('f' | 'x') -> price *. 0.8 *. 0.5 (* or just 0.4 *)
| Adult, ('f' | 'x') -> price *. 0.5 *. 0.5 (* or just 0.25 *)
| _ -> price
Looking at the logic here, we actually don't need to specify Adult, ('f' | 'x') because we know that we've already matched cases where when gender is 'f' or 'x', age is either Under_age or Legal. Thus we can use a wildcard _ for the pattern: _, ('f' | 'x').
The last pattern is a wildcard because we're matching any case that hasn't already been matched, and those values are not relevant to the outcome, so there's no point in binding name(s) to them.
let entry_price age gender =
let price = 12.0 in
match categorize_age age, gender with
| Under_age, _ -> failwith "Must be over 18 to enter"
| Legal, ('f' | 'x') -> price *. 0.8 *. 0.5 (* or just 0.4 *)
| _, ('f' | 'x') -> price *. 0.5 *. 0.5 (* or just 0.25 *)
| _ -> price
I'm trying to divide the data by a certain datetime.
I've created e_timefrom what was originally a string "2019-10-15 20:33:04" for example.
To obtain all the information from the string containing h:m:s, I uses the following command to create a double
gen double e_time = clock(event_timestamp, "YMDhms")
Now I get the result I want from format e_time %tc (human readable),
I want to generate a new variable anything that is greater than 2019-10-15 as 1 and anything less than that as 0 .
I've tried
// 1
gen new_d = 0 if e_time < "1.887e+12"
replace new_d = 1 if e_time >= "1.887e+12"
// 2
gen new_d = 0 if e_time < "2019-10-15"
replace new_d = 1 if e_time > "2019-10-15"
However, I get an error message type mismatch.
I tried converting a string "2019-10-15" to double \to check if 1.887e+12 really meant 2019-10-15 using display, but I'm not sure how the command really works here.
Anyhow I tried
// 3
di clock("2019-10-15", "YMDhms")
but it didn't work.
Can anyone give advice on comparing dates that are in a double format properly?
Your post is a little hard to follow (a reproducible data example would help a lot) but the error type mismatch is because e_time is numeric, and "2019-10-15" is a string.
I suggest the following:
clear
input str20 datetime
"2019-10-14 20:33:04"
"2019-10-16 20:33:04"
end
* Keep first 10 characters
gen date = substr(datetime,1,10)
* Check that all strings are 10 characters
assert length(date) == 10
* Convert from string to numeric date variable
gen m = substr(date,6,2)
gen d = substr(date,9,2)
gen y = substr(date,1,4)
destring m d y, replace
gen newdate = mdy(m,d,y)
format newdate %d
gen wanted = newdate >= mdy(10,15,2019) & !missing(newdate)
drop date m d y
list
+------------------------------------------+
| datetime newdate wanted |
|------------------------------------------|
1. | 2019-10-14 20:33:04 14oct2019 0 |
2. | 2019-10-16 20:33:04 16oct2019 1 |
+------------------------------------------+
I'm writing a script which calculates the date of Easter for years 1900 - 2099.
The thing is that for 4 certain years (1954, 1981, 2049, and 2076) the formula differs a little bet (namely, the date is off 7 days).
def main():
print "Computes the date of Easter for years 1900-2099.\n"
year = input("The year: ")
if year >= 1900 and year <= 2099:
if year != 2049 != 2076 !=1981 != 1954:
a = year%19
b = year%4
c = year%7
d = (19*a+24)%30
e = (2*b+4*c+6*d+5)%7
date = 22 + d + e # March 22 is the starting date
if date <= 31:
print "The date of Easter is March", date
else:
print "The date of Easter is April", date - 31
else:
if date <= 31:
print "The date of Easter is March", date - 7
else:
print "The date of Easter is April", date - 31 - 7
else:
print "The year is out of range."
main()
Exerything is working well but the 4 years computation.
I'm getting the:
if date <= 31:
UnboundLocalError: local variable 'date' referenced before assignment whenever I'm entering any of the 4 years as input.
You cannot chain a expression like that; chain the tests using and operators or use a not in expression instead:
# and operators
if year != 2049 and year != 2076 and year != 1981 and year != 1954:
# not in expression
if year not in (2049, 2076, 1981, 1954):
The expression year != 2049 != 2076 !=1981 != 1954 means something different, it is interpreted as (((year != 2049) != 2076) !=1981) != 1954 instead; the first test is either True or False, and neither of those two values will ever be equal to any of the other numbers and that branch will always evaluate to False.
You will still get the UnboundLocalError for date though, since your else branch refers to date but it is never set in that branch. When the else branch executes, all Python sees is:
def main():
print "Computes the date of Easter for years 1900-2099.\n"
year = input("The year: ")
if year >= 1900 and year <= 2099:
if False:
# skipped
else:
if date <= 31:
print "The date of Easter is March", date - 7
else:
print "The date of Easter is April", date - 31 - 7
and date is never assigned a value in that case. You need to calculate date separately in that branch still, or move the calculation of the date value out of the if statement altogether; I am not familiar with the calculation of Easter so I don't know what you need to do in this case.