Repository: adobe/react-spectrum
File: packages/@react-stately/datepicker/src/IncompleteDate.ts (TypeScript)

Code before:
      case 'minute':
        res.minute = cycleValue(res.minute ?? 0, amount, 0, 59, true);
        break;
      case 'second':
        res.second = cycleValue(res.second ?? 0, amount, 0, 59, true);
        break;
    }

    return res;
  }

  /** Converts the incomplete date to a full date value, using the provided value for any unset fields. */
  toValue(value: DateValue): DateValue {
    if ('hour' in value) {
      let hour = this.hour;
      if (hour != null) {
        hour = fromHourCycle(hour, this.dayPeriod ?? 0, this.hourCycle);
      } else if (this.hourCycle === 'h12' || this.hourCycle === 'h11') {
        hour = this.dayPeriod === 1 ? 12 : 0;
      }

      // if we have a time zone, return the zoned date time with the new offset if any
      if ('timeZone' in value && this.offset != null && this.year != null && this.month != null && this.day != null && hour != null && this.minute != null) {
        let date = new ZonedDateTime(this.calendar, this.era ?? value.era, this.year, this.month, this.day, value.timeZone, this.offset, hour, this.minute, this.second ?? 0, this.millisecond ?? 0);
        return date;
      }

      return value.set({
        era: this.era ?? value.era,
        year: this.year ?? value.year,
        month: this.month ?? value.month,
        day: this.day ?? value.day,
        hour: hour ?? value.hour,
        minute: this.minute ?? value.minute,
        second: this.second ?? value.second,
        millisecond: this.millisecond ?? value.millisecond
      });
    } else {
      return value.set({
        era: this.era ?? value.era,
        year: this.year ?? value.year,
        month: this.month ?? value.month,
        day: this.day ?? value.day
      });
    }
  }

  getSegmentLimits(type: string): {value: number | null, minValue: number, maxValue: number} | undefined {
    switch (type) {
      case 'era': {
        let eras = this.calendar.getEras();

Review comment (suggestion):
I was trying to avoid directly depending on `ZonedDateTime` and other types so that tree shaking could be more effective. Ideally `value.set` would accept an `offset` parameter, but short of that we could adjust it afterward like this:

```ts
let res = value.set({...});

if ('offset' in res && this.offset != null && res.offset !== this.offset) {
  res = res.add({milliseconds: res.offset - this.offset});
}
```

Code after:
      } else if (this.hourCycle === 'h12' || this.hourCycle === 'h11') {
        hour = this.dayPeriod === 1 ? 12 : 0;
      }

      let res = value.set({
        era: this.era ?? value.era,
        year: this.year ?? value.year,
        month: this.month ?? value.month,
        day: this.day ?? value.day,
        hour: hour ?? value.hour,
        minute: this.minute ?? value.minute,
        second: this.second ?? value.second,
        millisecond: this.millisecond ?? value.millisecond
      });

      if ('offset' in res && this.offset != null && res.offset !== this.offset) {
        res = res.add({milliseconds: res.offset - this.offset});
      }

      return res;
    } else {
      return value.set({
        era: this.era ?? value.era,
        year: this.year ?? value.year,
        month: this.month ?? value.month,
        day: this.day ?? value.day
      });
    }
  }

  getSegmentLimits(type: string): {value: number | null, minValue: number, maxValue: number} | undefined {
    switch (type) {
      case 'era': {
        let eras = this.calendar.getEras();
        return {
          value: this.era != null ? eras.indexOf(this.era) : eras.length - 1,
          minValue: 0,
          maxValue: eras.length - 1
        };
      }
      case 'year':
        return {
          value: this.year,
          minValue: 1,
          maxValue: 9999
        };
      case 'month':
        return {
          value: this.month,
          minValue: 1,
          maxValue: this.calendar.getMaximumMonthsInYear()