Laden...

DateOnly und TimeOnly - die neuen Typen in .NET 6

Erstellt von Abt vor 2 Jahren Letzter Beitrag vor einem Jahr 1.723 Views
Abt Themenstarter:in
16.830 Beiträge seit 2008
vor 2 Jahren

Wenn DateTime* jetzt noch zusätzlich TimeOnly liefert macht es die Nutzung von DateTime* nur komplexer.

Ganz einfache Regel:
DateTime hat überhaupt keine Daseinsberechtigung mehr, ausser Legacy Code.
DateTimeOffset all the way.

Und zukünftig wird man dann auch zwischen TimeSpan/TimeOnly hin und her konvertieren müssen.

Es macht immer mehr Sinn sich erst mal die Klassen und deren Zweck anzuschauen, statt sowas zu schreiben.
Denn TimeSpan hat mir TimeOnly wirklich gar nichts am Hut und da wird man auch nichts konvertieren müssen 🙂

90% des Beitragsinhalts stimmt nich, weil Du Dir das nicht angeschaut hast 🙂 Nimm Dir doch erstmal 2 Minuten vor dem Post Zeit, les es Dir durch: dann wirds Dir klar.

So ganz klar ist mir also noch nicht warum nun TimeOnly eingeführt wird.

Nach DateOnly / TimeOnly wird seit ca. 2005 gefragt und es gab immer wieder große, sehr aktive GitHub Diskussionen dazu, wie man es implementiert.
Gab auch schon erste Versuche bei .NET Standard dazu, hat das dann aber verschoben.

Ich hab dazu erst heut ne Slide veröffentlicht: DateTime vs. DateTimeOffset in .NET Slide 6: DateOnly und TimeOnly
Der offizielle Blog Post ist https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6

In .NET sind Zeiten eigentlich ganz klar strukturiert (lässt man Legacy weg)

  • DateTimeOffset für absolute, eindeutige Zeitangaben
  • DateOnly und TimeOnly für individuelle, nicht-eindeutige Zeitpunkte
  • TimeSpan für Zeitdauer

PS: hab [FAQ] DateTime vs. DateTimeOffset und der Umgang mit Zeiten in .NET um DateOnly und TimeOnly erweitert.

Edit: Hmpf, da war Papst schneller. Hätte nich mitten in meiner Antwort die FAQ aktualisieren sollen 🙂

T
2.223 Beiträge seit 2008
vor 2 Jahren

@Abt
Dann hab ich in den letzten Jahren irgendwas richtig gemacht.
Ich habe mit DateTime/TimeSpan bisher alles abdecken können ohne ein DateOnly/TimeOnly zu benötigen.
Die neuen Typen haben schon ihren Sinn und Zweck, dass will ich nicht bestreiten.

Aber alleine um schon mit dem Meer an Libs arbeiten zu können, die TimeSpan/DateTime verwenden/liefern wird es noch dauern bis sich die neuen Typen vollständig verwenden.
Ich rechne hier mit 2-3 Jahren bis die Libs Entwickler voll nachgezogen sind.
Vermutlich wird man hier noch einige Zeit zweigleisig fahren um beide Varianten anbieten zu können.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

Abt Themenstarter:in
16.830 Beiträge seit 2008
vor 2 Jahren

Auch hier vielleicht nicht die Vermutung aufstellen, sondern zB nen Blick auf GitHub werfen.
Einige große Libs und zB auch Microsoft Produkte (zB Entity Framework Core) haben bereits in ersten Vorab-Versionen die neuen Typen in fast-forward / non-breaking Change APIs.
Und .NET 6 is nich mal released, sondern aktuell in prev 6 (seit prev 4 mit den neuen Typen).

T
2.223 Beiträge seit 2008
vor 2 Jahren

@Abt
Einige Große Libs und Microsoft sind aber nicht alle Libs und vermutlich nicht mal die Libs, die wir heute verwenden.
Auch hier darf man nicht kurzsichtig sein und gleich einen großen Rollout von allen .NET Entwicklern erwarten.
Neue Typen brauchen auch erst ihre Zeit bis diese überall ankommen.
Und das ist leider ein Problem was nur über die Zeit erst gelöst wird.
Deshalb auch meine Meinung, dass dies 2-3 Jahre braucht bis es überall oder zu mindest im großen Stil ankommt.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

Abt Themenstarter:in
16.830 Beiträge seit 2008
vor 2 Jahren

DateTimeOffset existiert seit .NET 2.0, also seit 2006 und trotzdem verwenden viele .NET Entwickler DateTime, weil sie nicht verstehen / wissen, welcher Fehler in DateTime steckt 🙂
Aber Microsoft hat das damals auch nicht gut gemacht; man hätte den Typ abschaffen müssen oder zumindest viel härter informieren.

Ich seh fast täglich fehlerhafte APIs mit DateTime in Reviews. Ich hatte schon Kunden, die haben zehntausende von Euros in Fehlersuchen investiert und nachher wars die falsche Verwendung von DateTime, Time Zones und Zeitformaten.

Was ich damit sagen will:
In den Libs wird das sehr schnell kommen; in den Köpfen vieler vermutlich weniger 🙂
Das zeigt ja auch so bisschen zumindest Deine Antwort 🙂

P
441 Beiträge seit 2014
vor 2 Jahren

Ich sehe sehr häufig noch datetime Implementierungen -auch bei uns im Unternehmen.
Für Endanwender wird das meist dann sichtbar, wenn Charts angezeigt werden, die machen dann lustige Sprünge oder zeigen nur 23h Daten an Tagen mit Zeitzonenw-Offset-Wechsel.

T
2.223 Beiträge seit 2008
vor 2 Jahren

@Abt
Mir geht es nicht um DateTime/DateTimeOffset.
Das es die seit .NET 2.0 gibt ist mir klar, da ich schon seit 2007 mit .NET arbeite.
Mir geht es um DateOnly/TimeOnly.

Gibt es solche Api Erweiterungen in jeder Version von .NET oder nur bei LTS Versionen?
Falls es diese in jeder Version geben kann, kann dies ein Problem für die LTS Versionen werden.
Gerade wenn Api Erweiterungen direkt in Libs übernommen werden, wird man im schlimmsten Fall bei einer LTS Version mit alten Abhängigkeiten festhängen.
Dann gäbe es nur zwei Lösungen, entweder die Version Wechseln was die LTS Versionen aber komplett überflüssig machen würde oder man müsste eine LTS Version mit alten Abhängigkeiten laufen lassen.
Entsprechend müssten hier die Libs Entwickler zukünftig auch abwägen welchen Weg man gehen will.

Da .NET 6 die erste LTS Version im neuen Versionszyklus wird, wird sich erst mit den nächsten Versionen zeigen ob/wie hier dann die zukünftige Libs Entwicklung laufen wird.
Entsprechend fehlen hier auch noch die praktischen Erfahrungen, die sich erst noch zeigen müsssen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

Abt Themenstarter:in
16.830 Beiträge seit 2008
vor 2 Jahren

Vorweg: Hab das Thema in ein eigenen Thread verlagert

Mir geht es nicht um DateTime/DateTimeOffset.
Das es die seit .NET 2.0 gibt ist mir klar, da ich schon seit 2007 mit .NET arbeite.
Mir geht es um DateOnly/TimeOnly.

Die Historie zeigt allgemeinen Changes zwei Lager:

  • Devs, die sich selbst aktuell halten und Changes adaptieren
  • Devs, die das nicht tun, weil sie zB die Changes gar nicht mitbekommen

Die Entwickler von großen Libs, von Open Source Projekten gehören in 99,9999% zum ersten Lager, weshalb hier jegliche Ökosystem Changes auch schnell verbreiten; meistens als kompatible Fast Forward Changes. Daher siehst Du hier in den ensprechenden Preview-Versionen jetzt, nach wenigen Tagen, schon die ersten Implementierungen.
Entsprechend ist dann auch die Verbreitung hoch, wenn agile, moderne Projekte solches Übernehmen.

Und dann gibts da halt noch die - ich nenn sie mal - klassische Wasserfall-Welt von .NET; oft auch mit gestandenen .NET Entwicklern, die sich aus verschiedenen Gründen vielleicht nicht mehr so häufig über Changes informieren; Code oft jahrelang nur Pflegen, teilweise erweitern.
Da wird man solche Changes halt deutlich langsamer sehen.

Dass man nun in der Datenbank ein DateTimeOffset-Feld, das bisher fürs Geburtstag hergehalten hat, nun so schnell wie möglich sofort in ein DateOnly Feld umwandelt; ja, vermutlich bisschen übers Ziel hinaus geschossen.
Unnötig und nicht zweckdienlich.

Aber Deine allgemeine Aussage, dass das 2-3 Jahre dauern wird: na, da zeigt wie gesagt die Historie ein völlig anderes Verhalten 🙂
Würde entsprechend nicht darauf setzen; das geht schneller, viel schneller.

Gibt es solche Api Erweiterungen in jeder Version von .NET oder nur bei LTS Versionen?

Ähm, wat? Nein, Nein, LTS hat damit gaaar nichts zutun.
LTS hat nichts mit Content zutun. LTS bedeutet Long-Term-Support. Da gibts auch keine Probleme.
Hier gehts also nicht darum, dass neue Inhalte kommen oder um Kompatibilitäten, sondern um Patches.
Du vermischt da nun einige Sachen, die in sich nichts miteinander zutun haben.

Größere Änderungen aller Art können mit jedem Major Update kommen (beachtet man die SemVer Konventionen, die .NET erfüllt).
Schau Dir nochmal an, was der Sinn einer LTS ist und was er mit Content Changes zutun hat 🙂

Entsprechend müssten hier die Libs Entwickler zukünftig auch abwägen welchen Weg man gehen will.

Auch das nicht.

Für Entwickler ändert sich mit LTS genau: nichts.
Entwickler können komplett wie bisher agieren: Geringste Vorgabe der .NET Version, die inhaltlich sinnvoll ist.
LTS hat auch hier wirklich nichts, gar nichts zutun.

Da .NET 6 die erste LTS Version im neuen Versionszyklus wird, wird sich erst mit den nächsten Versionen zeigen ob/wie hier dann die zukünftige Libs Entwicklung laufen wird.
Entsprechend fehlen hier auch noch die praktischen Erfahrungen, die sich erst noch zeigen müsssen.

Nein, auch das nicht 🙂
Die praktischen Erfahrungen von SemVer sind schon Jahrelang vorhanden, auch hier LTS: keinerlei Aktien.
.NET ist hier auch nicht das einzige Ökosystem, in dem das so ist; das ist quasi in allen Ökosystemen so.

Dass es in .NET überhaupt LTS gibt liegt an der Release Geschwindigkeit: diese ist nun eher dem agilen Modell entsprechend, deutlich häufiger; es gibt alle 6 Monate ein Major Release und jedes zweite (immer gerade Zahlen) ist ein LTS.
Da braucht .NET LTS im Sinne des reliability engineering, wie man es eben aus anderen Ökosystemen gewöhnt ist. Die Bindung an den Betriebssystem Support, wie es mit .NET Framework der Fall war, ist entsprechend ja weggefallen.

T
2.223 Beiträge seit 2008
vor 2 Jahren

@Abt
Okay, dann waren meine Sorgen in dem Fall unbegründet.
Ich habe halt das Problem, dass ich beruflich nur mit .NET Framework arbeiten kann.
Hier kann ich nur begrenzt Einfluss darauf nehmen, dass wir die Projekte nach und nach in Richtung .NET 5+ pushen da uns auch für solche Umstellungen einfach die Leute fehlen.
Wir sind in einer Region wo es leider auch einen Mangel an Entwicklern gibt allen voran C#/.NET Entwicklern.

Wir haben bei uns noch Web Anwendungen die eben noch auf Web Forms basieren, also wirklich tote Technik.
Entsprechend müssten wir die UI komplett neu machen, was aber wegen der begrenzten Kapazitäten bei uns ein langwieriger Prozess wird.
Hier ist wohl schon angedacht eine parallele Entwicklung zubetreiben.
Sprich auf der einen Seite die UI neu zu machen sowie den Unterbau auf .NET 5+ zu portieren und auf der anderen Seite dann die bestehende Version weiter supporten.

Unser erster Versuch von 2015/2016 ist wegen diesem Mangel an Leuten auch gescheitert.
Damals haben wir versucht auf .NET Core umzusteigen und den Code sogar komplett neuzumachen.
Da wir für andere Projekte wieder den Großteil der Leute abziehen musten, ist das Thema damals leider versandet.

Entsprechend bin ich in der Situation den Code auf .NET Framework weiter zu pflegen und auch noch zu erweitern.
Ich kann hier also keinen Sprung auf .NET 6 o.ä. vornehmen auch wenn ich es gerne wollte.
Gute Gründe für einen Wechsel gibt es genug.

Meinem AG habe ich die Situation auch bereits 2019 erklärt und ihm auch gesagt, dass Framework ebend ein Abstellgleis ist.
Da wir die UI für unser Projekt erst neu gemacht hatten, will dieser nicht die nächste Großbaustelle auf machen.
Deshalb muss ich eben auch schauen, dass ich das Projekt so lange wie möglich supporten und weiter entwickeln kann.

Daher auch meine Sorge, dass wir ebend irgendwann in der Situation sind in dem die Abhängigkeiten der Projekte nicht mehr auf Framework supportet werden.
Zwar wäre dies dann ein guter Zeitpunkt um dem AG darauf hinzuweisen, dass der Wechsel kommen muss.
Besser wäre es natürlich wenn wir schon lange vorher den Sprung machen.
Aber aktuell wird dies wohl auch erst in ein paar Jahren passieren.

Ich selbst würde mich natürlich freuen, wenn wir den Sprung machen.
Gerade um die alte Technik endlich durch moderne und performantere Lösungen zu ersetzen wäre ein Traum.
Auch um eine supportete Technik zu haben und um die ganzen Performance Hacks wieder los zu werden. 🙂

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

Abt Themenstarter:in
16.830 Beiträge seit 2008
vor 2 Jahren

Ist auch überhaupt nicht schlimm, dass Du noch mit alter .NET Technik unterwegs bist; vermutlich sind das die meisten Entwickler.
Das ist vollkommen okay.

Aber dann schau Dir doch einfach gewisse Themen wie LTS an, wenn sie neu für Dich sind, statt einen Mischmasch aus zusammenhanglosen Fehlinfos zu schreiben 🙂
Das hilft Dir nicht, und anderen erst recht nicht 🙂

T
2.223 Beiträge seit 2008
vor 2 Jahren

@ABt
Hast recht, mache ich die Tage 🙂

Ich plane aktuell auch schon ein Testweb umzusetzen und mich in die neue Basis von ASP .NET 5+ sowie generell von den neuen .NET Techniken einzuarbeiten.
Letztes Wochenende habe ich auch die Zeit genutzt und mal etwas mehr mit EF5 zu arbeiten und ein paar Tests zu fahren.
Entsprechend baue ich mir hier schon die Erfahrungen nach und nach auf um eben nicht wieder bei 0 anzufangen, wenn wir den Wechsel irgendwann mal starten.
Und zu lange will ich das auch nicht aufschieben, da es dann nur um somehr zu lernen gäbe was dann enorm viel Zeit bräuchte.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

J
641 Beiträge seit 2007
vor 2 Jahren
DateTimeOffset

Aber warum soll DateTime überhaupt keine daseinsberechtigung mehr haben?
Wir haben eine große Software die nutzt im Backend nur DateTime. Das Backend nutzt aber auch nur DateTime angaben in UTC, das Frontend ist in HTML/JS

Warum sollten wir nun im Backend allen möglichen Code ändern, wenn wir DateTime sowieso nur als UTC nutzen. Da brauchen wir den Offset ja nicht.

cSharp Projekte : https://github.com/jogibear9988

Abt Themenstarter:in
16.830 Beiträge seit 2008
vor 2 Jahren

Wenn Du immer noch sagst "wir brauchen Offset nicht", dann hast Du es immer noch nicht verstanden 🙂

Eine technische Sache verliert ihre Daseinsberechtigung, wenn es einen vollständigen Ersatz gibt.
Und DateTimeOffset ersetzt eben DateTime und hat Designkorrekturen.

Aus .NET Sicht ist aber die Verwendung trotzdem problematisch, weil euch bei Schnittstellen eben Informationen verloren gehen können, zB bei Bibliotheken, Serialisierung, APIs etc.
Das sieht man zB an der Kind-Eigenschaften, die dann nicht mehr stimmt und fehlerhafte Berechnungen auslösen kann.
Es fällt aber den meisten nicht auf.

In der .NET Doku ist das mittlerweile gut beschrieben: DateTime stellt keine absolute Zeitdarstellung dar. Es ist leider so einfach nicht implementiert worden. Das erfüllt nur DateTimeOffset.
Die Migration - besonders wenn man eh explizit mit DateTime UTC arbeitet - ist aber super simpel: einfach DateTime durch DateTimeOffset ersetzen und nie wieder sorgen machen.

Abt Themenstarter:in
16.830 Beiträge seit 2008
vor 2 Jahren

Hier mal ein ganz banales Beispiel:

DateTime und die Problematik der Zeitzonen-Behandlung:


// Aktuelle UTC Zeit - Dateime Kind ist durch UtcNow korrekterweise Utc
DateTime dt = DateTime.UtcNow;
Console.WriteLine(dt.ToString("HH:mm")); // Hier kommt aktuell 0746 raus

// String als ISO 8601, wie man es zB tun sollte bei HTTP APIs (ASP macht das automatisch) und zB auch bei jeder Art Zeitangaben in Textdateien
string apiReturn = dt.ToString("o");

// zurück als DateTime -> DateTime Kind ist nun Local - Verfälschung der Zeitangabe
DateTime apiValue = DateTime.ParseExact(apiReturn, "o", null);
Console.WriteLine(apiValue.ToString("HH:mm")); // hier kommt 0946 raus

Obwohl gar nicht gewollt muss DateTime immer explizit verwendet werden, weil die Zeit nicht neutral, standardisiert behandelt wird.
Ansonsten - siehe Output - stimmt die Zeitrelation plötzlich nicht mehr.

Und diese Notwendigkeit, dass DateTime explizit programmiert werden muss ist, die Quelle vieler Fehler; vor allem wenn man das eben nicht weiß.
Ich persönlich habe noch keine einzige große Anwendung gesehen, die mit DateTime arbeitet und KEINEN Zeitzonenfehler hat - weil man mit DateTime eben diesen Fehler so extrem einfach und unscheinbar begeht.
Die Information der Eindeutigkeit geht in DateTime immer verloren. Dir hilft das "Wir nutzen nur UTC" also nur bedingt.

Hingegen DateTimeOffset: es wird immer die absolute Zeit verwendet - implizit.
Es ist keinerlei Korrektur notwendig.


DateTimeOffset dt = DateTimeOffset.UtcNow;
Console.WriteLine(dt.ToString("HH:mm")); // hier kommt 0749 raus

string apiReturn = dt.ToString("o");

DateTimeOffset apiValue = DateTimeOffset.ParseExact(apiReturn, "o", null);
Console.WriteLine(dt.ToString("HH:mm")); // hier kommt 0749 raus

Noch Problematischer ist zB. die Verwendung von DateTime eben mit der Datenbank (siehe mein Artikel dazu).
Dort geht beim Schreiben die Zeitzone vollständig verloren und beim Lesen ist sie Unspecified.

Du kannst mit DateTime durchaus sicher umgehen: aber nie ohne zusätzliche, explizite Programmierung.
Und das ist eine riesige Fehlerquelle.

309 Beiträge seit 2020
vor 2 Jahren

Steht ja auch genauso in der Doku:

Vergleichen von DateTime, DateTimeOffset, TimeSpan und TimeZoneInfo

These uses for DateTimeOffset values are much more common than those for DateTime values. As a result, consider DateTimeOffset as the default date and time type for application development.

709 Beiträge seit 2008
vor 2 Jahren

Gibt es eine Möglichkeit einzustellen, dass Fehler - oder zumindest Warnungen - generiert werden, wenn man im Code DateTime verwendet?

Abt Themenstarter:in
16.830 Beiträge seit 2008
vor 2 Jahren

Es gibt Compiler Analyzer für Roslyn.
Edit: gerade geschaut, es gibt vor allem Analyzer, die bei der Verwendung von DateTime.Now warnen.
Vllt die Gelegenheit einen passenden Analyzer hier zu schreiben.

S
40 Beiträge seit 2022
vor einem Jahr

In Bezug auf DateTime und DateTimeOffset kommen einige fragen auf.

Laut Combiler ist es möglich DateTime mit DateTimeOffset zu mischen, aber was sagen die Professionisten dazu?

z.B


            DateTimeOffset dt = DateTime.UtcNow;
            Console.WriteLine(dt.ToString("HH:mm")); // Hier kommt aktuell 0746 raus

            // String als ISO 8601, wie man es zB tun sollte bei HTTP APIs (ASP macht das automatisch) und zB auch bei jeder Art Zeitangaben in Textdateien
            string apiReturn = dt.ToString("o");

            // zurück als DateTime -> DateTime Kind ist nun Local - Verfälschung der Zeitangabe
            DateTimeOffset apiValue = DateTime.ParseExact(apiReturn, "o", null);
            Console.WriteLine(apiValue.ToString("HH:mm")); // hier kommt 0746 raus

Wenn man einen DateTime-Wert übernimmt und diesen in einem DateTimeOffset speichert, mit dieser Variable dann arbeitet, könnt ihr euch vorstellen, dass es zu komplikationen kommen könnte?

Wird die DateTime in dem Fall durch den Combiler in eine DateTimeOffset convertiert?

danke für eure Antworten im Voraus!

P
441 Beiträge seit 2014
vor einem Jahr

Die Konvertierung von DateTime nach DateTimeOffset funktioniert über einen impliziten Cast.

Aus dem Quellcode von DateTimeOffset:


public static implicit operator DateTimeOffset(DateTime dateTime)

Die Konvertierung sorgt dafür, dass wenn du eine DateTime Objekt übergibts, dass als Kind "Local" ist, die Zeitzone des aktuellen, den Code ausführenden Systems an das neue DateTimeOffset objekt übergeben wird. Ist dein DateTime Objekt UTC, wird ein DateTimeOffset objekt mit Offset = 0 erzeugt.

Es kann dabei zu Problemen kommen, wenn du ein Datum auf einem System verarbeitest, dass in einer anderen Zeitzone steht und du dies nicht erwartest.
Ich würde nach Möglichkeit darauf verzichten DateTime und DateTimeOffset zu mischen.

S
40 Beiträge seit 2022
vor einem Jahr
  
            DateTimeOffset dt = DateTime.UtcNow;  
            Console.WriteLine(dt.ToString("HH:mm")); // Hier kommt aktuell 0746 raus  
  
            // String als ISO 8601, wie man es zB tun sollte bei HTTP APIs (ASP macht das automatisch) und zB auch bei jeder Art Zeitangaben in Textdateien  
            string apiReturn = dt.ToString("o");  
  
            // zurück als DateTime -> DateTime Kind ist nun Local - Verfälschung der Zeitangabe  
            DateTimeOffset apiValue = DateTime.ParseExact(apiReturn, "o", null);  
            Console.WriteLine(apiValue.ToString("HH:mm")); // hier kommt 0746 raus  
  

Kann meinen Beitrag leider nicht mehr editieren, der Code ist natürlich falsch. Es kann nur DateTime.UTCNow als DateTime übergeben werden. Die String-Konvertierung muss DateTimeOffset sein.

@Papst danke dir für deine Antwort.

J
641 Beiträge seit 2007
vor einem Jahr

Was man auch noch beachten muss, DateTimeOffset braucht 2Byte Speicher mehr als DateTime, da es intern eine DateTime Struktur und ein Int16 für das Offset verwendet.

Hier ist auch noch beschrieben das es mit DateTimeOffset auch noch Probleme gibt:
TimeZones and DateTimeOffset · Issue #360 · dotnet/runtime

cSharp Projekte : https://github.com/jogibear9988

Abt Themenstarter:in
16.830 Beiträge seit 2008
vor einem Jahr

Was meinst Du mit "Probleme" bei DateTimeOffset? Meinst den Satz

Note that in most cases DateTimeOffset is also not the proper domain type, as non-absolute-instant information is usually better recorded as a DateTimeZoned (which automatically updates the offset when adding any time).

Nun, dass ein Datentyp mit absoluter Information nicht für "non-absolute-instant information" Szenarien funktioniert: klar.
Aber deswegen haben wir ja nun auch endlich DateOnly und TimeOnly. (Man kann halt auch kein int verwenden und sich dann wundern, dass keine Kommazahlen raus kommen.

Und auch der Satz

also DateTimeOffset ToLocal assume the servers date time / timezone which does not give any option to convert to a users time zone for an application on the web, the client may be in a different timezone than the browser client.

ist selbstverständlich, weil DateTimeOffset den Client schließlich nicht kennt. Da helfen aber andere Runtimes / Frameworks / Libraries nicht. Das ist ja was fundamentales, wie Software funktioniert und welche Informationen zur Verfügung stehen.
Man braucht immer die externe Information, in welcher Zeitzone der Client sich befindet, um das konvertieren zu können - egal was man verwendet.

Sehe da also keine "weiteren" Probleme, für die DateTimeOffset verantwortlich sein soll.