web-dev-qa-db-fra.com

Un type pour Date uniquement en C # - pourquoi n'y a-t-il pas de type Date?

Dans notre projet C #, nous avons besoin de représenter une date sans heure. Je connais l'existence de DateTime, cependant, il intègre également une heure de la journée. Je veux préciser que certaines variables et arguments de méthodes sont basés sur la date. Par conséquent, je ne peux pas utiliser le DateTime.Date propriété

Quelles sont les approches standard à ce problème? Je ne suis sûrement pas le premier à rencontrer cela? Pourquoi n'y a-t-il pas de classe Date en C #?

Quelqu'un at-il une implémentation de Nice utilisant une structure et peut-être des méthodes d’extension sur DateTime et implémentant peut-être des opérateurs tels que == et <,>?

92
Carlo V. Dango

Permettez-moi d'ajouter une mise à jour à cette question classique:

  • La bibliothèque = Heure Noda de Jon Skeet est maintenant bien mature et possède un type de date uniquement appelé LocalDate. (Local dans ce cas signifie simplement local de quelqu'un , pas nécessairement local de l'ordinateur sur lequel le code est en cours d'exécution.)

  • Un type de date uniquement appelé Date est un ajout proposé au .NET Core, via le projet corefxlab . Vous le trouverez dans le package System.Time, Avec un type TimeOfDay et plusieurs méthodes d'extension aux types existants.

J'ai étudié ce problème de manière significative, donc je vais aussi partager plusieurs raisons pour la nécessité de ces types:

  1. Il existe une différence logique entre une valeur de date uniquement et une valeur de date à minuit.

    • Chaque jour local n'a pas un minuit dans chaque fuseau horaire. Exemple: la transition d’heure avancée du printemps du Brésil fait avancer l’horloge de 11h59:59 à 01:00:00.

    • Une date-heure fait toujours référence à une heure spécifique de la journée, tandis qu'une date seulement peut faire référence au début du jour, à la fin du jour ou à l'ensemble entier plage du jour.

  2. Si vous associez une heure à une date, la date peut changer lorsque la valeur est transmise d'un environnement à un autre, si les fuseaux horaires ne sont pas surveillés de très près. Cela se produit généralement en JavaScript (dont l'objet Date est réellement une date + heure), mais peut également se produire également en .NET, ou dans la sérialisation lorsque les données sont transmises entre JavaScript et .NET.

  3. La sérialisation d'un DateTime avec XML ou JSON (et d'autres) inclura toujours , même si ce n'est pas important. C'est très déroutant, en particulier si l'on considère des dates telles que les dates de naissance et les anniversaires, où l'heure n'a pas d'importance.

  4. Sur le plan architectural, DateTime est un DDD objet de valeur , mais il enfreint le principe de responsabilité unique). de plusieurs manières:

    • Il est conçu comme un type date + heure, mais est souvent utilisé comme date uniquement (en ignorant l'heure) ou en heure seule (en ignorant la date). (TimeSpan est également souvent utilisé pour l'heure, mais c'est un autre sujet.)

    • La valeur DateTimeKind attachée à la propriété .Kind Divise le type unique en trois. Le type Unspecified est vraiment l'intention initiale de la structure et doit être utilisé de cette façon. Le type Utc aligne spécifiquement la valeur sur UTC et le type Local aligne la valeur sur le fuseau horaire local de l'environnement.

      Le problème avec un indicateur distinct pour chaque type est que chaque fois que vous utilisez un DateTime, vous êtes supposé vérifier .Kind pour décider quel comportement adopter. Les méthodes-cadres le font toutes, mais d'autres l'oublient souvent. Il s'agit véritablement d'une violation SRP, car le type a maintenant deux raisons différentes de changer (la valeur et le type).

    • Ces deux méthodes conduisent à des utilisations d'API qui compilent, mais sont souvent absurdes ou ont d'étranges cas Edge causés par des effets secondaires. Considérer:

      // nonsensical, caused by mixing types
      DateTime dt = DateTime.Today - TimeSpan.FromHours(3);  // when on today??
      
      // strange Edge cases, caused by impact of Kind
      var london = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
      var paris = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time");
      var dt = new DateTime(2016, 3, 27, 2, 0, 0);  // unspecified kind
      var delta = paris.GetUtcOffset(dt) - london.GetUtcOffset(dt);  // side effect!
      Console.WriteLine(delta.TotalHours); // 0, when should be 1 !!!
      

En résumé, bien qu'un DateTime puisse être utilisé pour une date uniquement, il ne devrait le faire que lorsque chaque lieu qui l'utilise veille à ignorer l'heure et à ne pas essayer de convertir vers et depuis l'UTC ou d'autres fuseaux horaires.

40
Matt Johnson-Pint

Je soupçonne qu’il n’existe pas de classe pure Date dédiée car vous avez déjà DateTime qui peut le gérer. Avoir Date conduirait à la duplication et à la confusion.

Si vous voulez l’approche standard, regardez le DateTime.Date propriété qui ne donne que la date d'un DateTime avec la valeur de l'heure définie sur 12:00:00 minuit (00:00:00).

17
Robert MacLean

J'ai envoyé un email à [email protected] et c'est leur réponse

Marcos, ce n’est pas un bon endroit pour poser des questions comme celles-là. Essayez http://stackoverflow.com La réponse courte est que vous avez besoin d'un modèle pour représenter un point dans le temps, et que DateTime le fait, c'est le scénario le plus utile. pratique . Le fait que les humains utilisent deux concepts (date et heure) pour marquer des points dans le temps est arbitraire et qu'il n'est pas utile de les séparer.

Ne découplez les cas où cela est justifié, ne faites pas les choses juste pour faire les choses à l’aveugle. Pensez-y de cette façon: quel problème avez-vous qui soit résolu en scindant DateTime en Date et Heure? Et quels problèmes aurez-vous que vous n’avez pas maintenant? Conseil: si vous examinez les utilisations de DateTime sur le framework .NET: http://referencesource.Microsoft.com/#mscorlib/system/datetime.cs#df6b1eba7461813b#references Vous verrez que la plupart d'entre elles sont en cours retourné d'une méthode. Si nous n’avions pas un seul concept comme DateTime, vous auriez à utiliser des paramètres ou Tuples pour renvoyer une paire Date/Heure.

HTH, Kirill Osenkov

Dans mon courrier électronique, je me demandais si c’était parce que DateTime utilise TimeZoneInfo pour obtenir l’heure de la machine - en toute propriété maintenant. Donc, je dirais que c'est parce que "les règles de gestion" sont "trop ​​couplées", elles me l'ont confiée.

11
MVCDS

J'ai créé un simple Date struct pour les moments où vous avez besoin d'une date simple sans vous soucier de l'heure, du fuseau horaire, du lieu local par rapport au lieu choisi, etc.

https://github.com/claycephus/csharp-date

10
Clay

Si vous devez effectuer des comparaisons de dates, utilisez

yourdatetime.Date;

Si vous affichez à l'écran utiliser

yourdatetime.ToShortDateString();
4
MattP

Permettez-moi de spéculer: c'est peut-être parce que jusqu'à SQL Server 2008, il n'y avait pas de type de données Date dans SQL, donc il serait difficile de le stocker dans SQL Server? Et c'est après tout un produit Microsoft?

3
Pleun

Qui sait pourquoi c'est comme ça. Il y a beaucoup de mauvaises décisions de conception dans le framework .NET. Cependant, je pense que ceci est assez mineur. Vous pouvez toujours ignorer la partie heure. Ainsi, même si un code décide de faire en sorte que DateTime fasse référence à plus que la date, le code qui s’intéresse ne doit jamais examiner que la partie date. Vous pouvez également créer un nouveau type ne représentant qu'une date et utiliser les fonctions de DateTime pour effectuer des tâches lourdes (calculs).

2
siride

Pourquoi? Nous ne pouvons que spéculer et cela n’aide pas beaucoup à résoudre les problèmes d’ingénierie. Une bonne hypothèse est que DateTime contient toutes les fonctionnalités qu'une telle structure aurait.

Si cela vous importe vraiment, enveloppez simplement DateTime dans votre propre structure immuable qui n’expose que la date (ou regardez le DateTime.Date propriété).

2
jason

Il y a toujours le DateTime.Date propriété qui coupe la partie temps de la DateTime. Peut-être que vous pouvez encapsuler ou encapsuler DateTime dans votre propre type de date.

Et pour la question pourquoi, eh bien, je suppose que vous devrez demander à Anders Heljsberg.

2
Mikael Östberg

En plus de la réponse de Robert, vous avez également le DateTime.ToShortDateString méthode. De plus, si vous vouliez vraiment un objet Date, vous pouvez toujours utiliser le modèle Adapter et envelopper l’objet DateTime pour n’exposer que ce que vous voulez (c.-à-d. Mois, jour, année).

2
Matt

Parce que pour connaître la date, vous devez connaître l'heure système (en ticks), qui comprend l'heure - alors pourquoi jeter ces informations?

DateTime a une propriété Date si vous ne vous souciez pas du tout de l'heure.

1
Massif

Oui, System.DateTime est également scellé. J'ai vu des gens jouer à ce jeu en créant une classe personnalisée uniquement pour obtenir la valeur de chaîne de l'heure mentionnée dans les publications précédentes, par exemple:

class CustomDate
{
    public DateTime Date { get; set; }
    public bool IsTimeOnly { get; private set; }

    public CustomDate(bool isTimeOnly)
    {
        this.IsTimeOnly = isTimeOnly;
    }

    public string GetValue()
    {
        if (IsTimeOnly)
        {
            return Date.ToShortTimeString();
        }

        else
        {
            return Date.ToString();
        }
    }
}

C'est peut-être inutile, car vous pourriez facilement extraire GetShortTimeString à partir d'un ancien type DateTime sans une nouvelle classe.

1
kd7

Si vous utilisez les propriétés Date ou Today pour obtenir uniquement la partie date de l'objet DateTime.

DateTime today = DateTime.Today;
DateTime yesterday = DateTime.Now.AddDays(-1).Date;

Ensuite, vous obtiendrez le composant date uniquement avec le composant heure défini sur minuit.

0
eph_tagh