New Issue: DateTime module stabilization - replace '.replace()'?

19073, "aconsroe-hpe", "DateTime module stabilization - replace '.replace()'? ", "2022-01-21T15:18:17Z"

As part of the module reivew for DateTime, we identified the .replace family of methods on date, time, and datetime as a potential area of improvement.

Currently, those signatures are below and the current behavior of each is to return a new record with the fields given

  proc date.replace(year=0, month=0, day=0) { }

  proc time.replace(hour=-1, minute=-1, second=-1, microsecond=-1,
                    in tzinfo=this.tzinfo) { }

  proc datetime.replace(year=-1, month=-1, day=-1,
                        hour=-1, minute=-1, second=-1, microsecond=-1,
                        in tzinfo=this.tzinfo) { }

// used like
var today = new date(2022, 1, 21);
var tomorrow = today.replace(day=22);

The name replace could be misleading because it might suggest an in-place update, but this is consistent with the string.replace method which also returns a new string. With a return type in the proc signature, I would personally find the documentation clear on the behavior (eg. proc date.replace(year=0, month=0, day=0): date {}) and wouldn't feel strongly about a different name.

Another direction we discussed was splitting out the single method into multiple methods to handle each part. This is a similar direction to #16767, though the list begins to grow:

proc date.replaceYear(year): date {}
proc date.replaceMonth(month): date {}
proc date.replaceDay(day): date {}

proc time.replaceHour(hour): time {}
proc time.replaceMinute(minute): time {}
proc time.replaceSecond(second): time {}
proc time.replaceMicrosecond(microsecond): time {}
proc time.replaceTzinfo(tzinfo): time {} // ****

proc datetime.replaceYear(year): datetime {}
proc datetime.replaceMonth(month): datetime {}
proc datetime.replaceDay(day): datetime {}
proc datetime.replaceHour(hour): datetime {}
proc datetime.replaceMinute(minute): datetime {}
proc datetime.replaceSecond(second): datetime {}
proc datetime.replaceMicrosecond(microsecond): datetime {}
proc datetime.replaceTzinfo(tzinfo): datetime {} // ****

**** see #18941 for discussion on time zones, tzinfo, they are in flux

This is similar in spirit to java.time.LocalDate (and related classes) that have a withMonth, withYear, and withDayOfMonth methods. Those also return new objects.

One benefit here is that there is no potential confusion around the default args in the current methods. Besides date.replace using 0 as a sentinel as opposed to -1 like its siblings, these are perhaps not as precise as we might like. One downside is that you have to use method chaining to replace multiple fields like myDate.replaceYear(2021).replaceMonth(10).

Another possibility is to simply drop them because they are a thin convenience over writing new date(2021, mydate.month, mydate.day). I see the utility of these methods as a toss-up and would err towards dropping them unless we had a consistent pattern that we wanted to adopt across all standard modules (or at the language level with a "record update" or "functional update" feature like in OCaml (date with year=2021)).