F# Record Structural Comparison Ordering - f#

If I have an record such as:
type MyDate =
{ Year : int
Month : int
Day : int }
I know that F#'s structural comparison will ensure that when a list is sorted it will maintain a consistent order.
My question is whether I can rely on it to do the comparison in a specific way, and what that way is?
For example with the MyDate record above: if it compares each field in the order they were declared then I could assume the following:
{ Year: 2010; Month: 9: Day: 8 } > { Year: 2009; Month: 10; Day: 20 }
I've struggled to find the documentation that describes how the structure equality for Record types work. I can see from the Fsharp.Core tests how tuple comparison works: https://github.com/fsharp/fsharp/blob/cb6cb5c410f537c81cf26825657ef3bb29a7e952/tests/fsharp/core/attributes/test.fsx#L737, but I can't seem to find a similar test for Record types.

Ah, straight after I posted the question I managed to find the answer:
From the language spec: https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf
8.15.4 Behavior of the Generated CompareTo Implementations
...
• If T is a struct or record type, invoke FSharp.Core.Operators.compare on each corresponding pair of fields of x and y in declaration order, and return the first non-zero result.
So in the above MyDate example, when comparing two instances it will:
compare the Year fields first
then if the years are the same it will compare the Month fields
then if the months are the same it will compare the Day fields

Related

What Date Class is used in grails?

I want to get the 4-digit year from today.
I have a variable def todayDate = new Date() in my controller.
I googled to see how to do it. It pointed me to this page.
https://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Date.html
There is a method called toYear()
Actually, none of the methods in this document works. The Date class in this document is not the same Date class in the controller for sure.
Did Google show me the wrong document? What is the correct way to get the 4-digit year from a Date()?
I was reading and trying to understand all the comments and checking the links. I think I get what is going on here.
When I declare a Date variable in Grails, it is a java.util.Date. If I google how to work with the Date, this gets confusing. The methods that process the Date are not from the java.util.Date class. Majority of the java.util.Date methods are deprecated. The methods you can find from google are actually coming from the org.codehaus.groovy:groovy-dateutil:3.0.9 Groovy date enhancement package.
So, the Date is a java.util.Date but the methods are from the enhancement package.
tl;dr
You said:
I want to get the 4-digit year from today.
String.valueOf( LocalDate.now().getYear() ) // Java syntax.
2022
Avoid legacy classes
The java.util.Date class is terribly flawed. Along with Calendar and the other legacy date-time classes, these were years ago supplanted by the modern java.time classes defined in JSR 310.
Sun, Oracle, and the JCP community all gave up on these legacy classes. I suggest you do the same.
Year
(Forgive the Java syntax as I do not know Groovy.)
If all you want is the year, use Year class.
Year currentYear = Year.now( z ) ;
int y = currentYear.getValue() ;
LocalDate#getYear
For a date-only value, use LocalDate.
Time zone
Determining the current date requires a time zone. For any given moment, the date varies around the globe by time zone.
(Again, Java syntax.)
ZoneId z = ZoneId.of( "America/Edmonton" ) ; // Or, ZoneId.systemDefault() ;
LocalDate today = LocalDate.now( z ) ;
int year = today.getYear() ;
I do not see all these methods in your Groovy API documentation. Perhaps I do not know how that doc works. The classes listed here are built into Java 8 and later.

How to represent a date of birth in Dart?

Let's say I want to represent a person with their name and date of birth. I could write this in Dart:
class Person {
String name;
DateTime dateOfBirth;
}
The problem is that DateTime has a timezone offset so if I want to sort people by age then I need to implement my own Comparator callback function which only looks at the year, month and day properties of dateOfBirth.
An alternative is to add a class invariant to Person to ensure that the dateOfBirth is always in UTC, then my sort comparator becomes much simpler: (p1, p2) => p1.dateOfBirth.compareTo(p2.dateOfBirth)
Both these approaches feel wrong because I don't care about the timezone component - what I really want is a class which just represents (year, month, day) in the Gregorian calendar. I've found this class, but it's not very popular. Is there some standard Dart class that I can use? Or do most Dart programmers just use DateTime to represent such a concept?
Just make sure only year/month/day are included when saving the DoB.
date = getDobFromUser();
dob = DateTime(date.year, date.month, date.day);
If you need more granularity than that, you should include the time they were born and probably store it as milliseconds since the Unix epoch for easy sorting.

Parse week strings for comparison using Java 8

I want to compare string representations of weeks, e.g. week "01/17" is before "02/17" and after "52/16".
The following code throws an exception, I guess because my string doesn't hint at the exact day of each week. However, I don't care - it could all be Mondays or Thursdays or whatever:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ww/YY", Locale.GERMANY);
LocalDate date1 = formatter.parse(str1, LocalDate::from);
Do I need to modify the parser? Or parse to some other format? Unfortunatley there is no object like YearMonth for weeks...
One solution would be to always default to the same day, say the Monday. You could build a custom formatter for that:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendPattern("ww/YY")
.parseDefaulting(ChronoField.DAY_OF_WEEK, 1)
.toFormatter(Locale.GERMANY);
You can now build LocalDates representing the Monday of the given week:
LocalDate d1 = LocalDate.parse("01/17", fmt);
LocalDate d2 = LocalDate.parse("52/16", fmt);
System.out.println(d1.isAfter(d2));
which prints true because 01/17 is after 52/16.
I wasn't able to find a way for this to work with the DateTimeFormatter class, but I would like to suggest a different approach.
The Threeten Extra library contains a number of classes that were deemed too specific to include in the java.time library. One of them is the YearWeek class you mention.
Your problem can be solved by parsing the week-number and year manually from the input-string and then invoking the YearWeek creator-method like this:
YearWeek yw = YearWeek.of(year, monthOfYear);
tl;dr
YearWeek.parse( "2017-W01" )
ISO 8601
Or parse to some other format?
Yes, use another format.
Use the standard ISO 8601 formats when serializing date-time values to text. The standard includes support for week dates.
For a year-week that would be four year digits, a hyphen, a W, and two digits for the week of the year.
2017-W01
Get clear on your definition of a “week”. The ISO 8601 definition is that:
The Week # 1 contains the first Thursday of the year, and
Runs Monday-Sunday.
So years run either 52 or 53 weeks long. And note that under this definition, the first few days of the year may be in the prior year when week-numbering. Likewise, the last few days of the year may be in the following year when week-numbering.
If you want to indicate a particular day within that week, append a hyphen and a single digit running 1-7 for Monday-Sunday.
Tip: To see ISO 8601 week numbers by default on your computer, you may need to adjust your OS setting. For example, on macOS set System Preferences > Language & Region > Calendar > ISO 8601 to make apps such as Calendar.app to display week numbers with this standard definition.
2017-W01-7
By the way, a couple of similar representations:
An ordinal date meaning the year and the day-of-year-number running from 1-366 is year, a hyphen, and a three-digit number: 2017-123
Month-Day without year is two hyphens, month number, hyphen, and day-of-month number: --01-07
Note that the use of Locale as seen in the Question is irrelevant here with the standard ISO 8601 formats.
YearWeek
Unfortunatley there is no object like YearMonth for weeks...
Ahhh, but there is such a class.
For a class to directly represent the idea of a week-year, see the correct Answer by Henrik. That Answer shows the ThreeTen-Extra library’s class YearWeek.
The YearWeek class can directly parse and generate strings in standard format.
YearWeek yw = YearWeek.parse( "2017-W01" );
You can compare the YearWeek objects with methods: compareTo, equals, isBefore, isAfter.
yw.isBefore( thatYw )
The ThreeTen-Extra project offers other classes such as YearQuarter that you may find useful.

SPSS: Want to copy same datediff function across many different date variables and generate multiple result variables

I am very new to SPSS and statistical programs in general. I've searched for the answer to this question but can't seem to find a straightforward answer.
I have one date variable (dateA) that I want to compare to multiple other date variables (date1, date2, date3...date1000+) with the datediff function, and create a separate datediff result variable for each computation.
I have tried doing this through the "compute variable" process on SPSS but it only allows me to choose a pair of dates at a time (i.e. adding the "TO" function for date1 TO dateX doesn't work). I would rather create an automated process to do this function for all of these other date variables automatically, and create datediff results for each (datediff1, datediff2, datediff3...).
e.g. dateA - date1 = datediff1; dateA - date2 = datediff2; dateA - date3 = datediff3...and so on (without having to compute each manually which would take forever).
The end goal is to find out how many of these many datediff results are <= 2 weeks.
Thanks for your help!
First use this to create some sample data:
DATA LIST FREE /dateA date1 date2 date3 (4ADATE10).
BEGIN DATA
1/1/2017 1/2/2017 1/7/2017 1/12/2017
1/2/2017 1/16/2017 1/10/2017 1/14/2017
1/3/2017 1/29/2017 2/1/2017 2/7/2017
END DATA.
Now to create a new set of variables containing the difference between the dates you can use do repeat to loop through the dates and compare them:
do repeat DtList=date1 to date3/Diff=Diff1 to Diff3.
compute Diff=datediff(DtList, dateA, "weeks").
end repeat.
* now you can count the number of dates that have a two weeks difference or more.
COUNT Weeks2p=Diff1 Diff2 Diff3 (2 thru Hi).
But if all you need is to get the final count, you can do it without creating all the difference wariables, like this:
compute Weeks2p=0.
do repeat DtList=date1 to date3/Diff=Diff1 to Diff3.
compute Weeks2p=Weeks2p + (datediff(DtList, dateA, "weeks") ge 2).
end repeat.

rails split string with custom length

I'm using Rails and MongoMapper as my working platform.
I want to generate a custom key with the help of month and year. The possible format would be YYYYMM####,
YYYY is current YEAR which I can get as Date.today.strftime("%Y")
MM is current Month Which I can get as Date.tody.strftime("%m")
After that ### is incremented integer value
I get the last job with the code
jobForLastnum = Job.last(:order => :_id.desc)
lastJobNum = jobForLastnum.job_number
Now my question is I received the job_number as '201305100'
I want to split it with custom length like, ['2013','05','100']
I know how to split a string in ruby and I successfully did that but i got result as individual character like
['2','0','1','3','0','5','1','0','0']
With the help of this I could retrieve the year:
lastJobNum.to_s[0,4]
With the help of this I got the month:
lastJobNum.to_s[4,2]
But after that there is custom length string. How can I get all the data in a single array?
You can simply use ranges:
c = "2013121003"
[c[0..3], c[4..5], c[6..-1]]
You can also use String#unpack:
"20131210034".unpack("A4A2A*")
Or with regexp as suggested by tessi, using String#scan:
c = "2013121003"
c.scan(/(\d{4})(\d{2})(\d+)/)
In all cases, this will return an array with the year, month, and job id as strings.
A regexp can help you here.
jobNumber = 201305100
year, month, job_id = jobNumber.to_s.match(/(\d{4})(\d{2})(\d*)/)[1..3]
First, we convert the jobNumber to a String. Then we throw a regexp at it. The regexp has three capture groups ((\d{4}) four numbers for the year, (\d{2}) two numbers for the month, (\d*) any remaining number for the job_id).
The job_number.to_s.match(...) returns a MatchData object, which we can access by its first three capture groups with [1..3] (see the documentation).
Finally, we assign the resulting Array to our variables year, month, and job_id.
year
#=> 2013
month
#=> 05
job_id
#=> 100

Resources