Avatar billede boomshanka Nybegynder
16. marts 2010 - 12:15 Der er 11 kommentarer og
1 løsning

Hvor svært kan det være at regne med DateTime og TimeSpan

Hej eksperter,

Jeg har et tilsyneladende simpelt problem som er ved at drive mig til vanvid. Jeg er ved at lave en applikation som indenfor et givet scenarie (antal dage) kan fortælle mig om en given bruger har fødselsdag og hvor gammel vedkommende er. Scenariet kan enten være +/- en uge fra dags dato, samme dag eller 7 dage frem fra dags dato eller kun samme dag som dags dato. Jeg har endda opsat en unittest som tester applikationen imod en collection af DateTime instanser (fødselsdage) hvor dags dato også bliver stubbet, og det hele ser ud til at virke fint sålænge dags dato ikke ligger indenfor en uge fra nytår (24. december - 7. januar). Men så snart dags dato stubben ligger indenfor dette tidsrum begynder unittesten at fejle...

Jeg har efterhånden set på en del eksempler som alle projectere fødselsdagen frem til dags dato og udregner et TimeSpan således (for +/- en uge fra dags dato):

DateTime dt = new DateTime(todaysDate.Year, birthday.Month, birthday.Day);
double daySpan = Math.Abs(todaysDate.Substract(dt).TotalDays);
bool birthdayIsWithinSpan = (daySpan <= 7)


Dette vil dog ikke virke når todaysDate er tæt på nytåret, men jeg har endnu ikke kunne finde en tilfredsstillende løsning som løser problemet. Er der nogen som har et bud på hvordan det kunne løses?
Avatar billede erikjacobsen Ekspert
16. marts 2010 - 12:50 #1
Er problemet før årsskiftet ikke, at du bruger det aktuelle år: todaysDate.Year, men hvis personen har fødselsdag i januar, så skulle du bruge næste år?
Avatar billede boomshanka Nybegynder
16. marts 2010 - 14:00 #2
Jo, det er også et af de scenarier jeg har været igennem. Det er iøvrigt også gældende efter årsskiftet, men her skal fødselsdatoen ikke være næste år men indeværende år. På den måde bliver det lynhurtigt noget rodet kode - eksempelvis hvis både dags dato og fødselsdatoen ligger lige før nytår.
Avatar billede erikjacobsen Ekspert
16. marts 2010 - 14:08 #3
Øh, ja - rodet?

Er det ikke meget simpelt:

1) For en person beregnes antal dage fra nu til personens fødselsdag i indeværende år, og i efterføølgende år.

2) Hvis een af disse ligger mellem 0 og 7, så har vedkommende fødselsdag indenfor den næste uge.
Avatar billede boomshanka Nybegynder
16. marts 2010 - 15:44 #4
Men hvad hvis det i dag var d. 1. januar 2011 og vedkommende var født d. 28. december 2003? Så kommer han ikke med fordi der for det indeværende år ville være 362 dage til hans fødselsdag (eller 363 dage hvis det er skudår) og hhv. 727 og 728 dage i efterfølgende år for ikke-skudår og skudår. Det lyder umiddelbart nemt at rette (træk et år fra personens fødselsdag i indeværende år hvis dags dato netop er passeret nytår), men her er det så jeg synes koden bliver en anelse rodet :-)

Alt dette er inden man overhovedet begynder at overveje alderen på vedkommende, for alderen for en kommende fødselsdag skulle gerne vise hvor gammel personen bliver mens en passeret fødselsdag viser hvor gammel personen er. Jeg siger ikke det er umuligt - jeg savner bare et eksempel som passer.
Avatar billede erikjacobsen Ekspert
16. marts 2010 - 17:41 #5
Hvis du også skal kigge tilbage, skal du lave 3 beregninger: minus et år, aktuelt år, plus et år, og så finde ud om der er een af de tre, der er tilstrækkeligt tæt på.
Avatar billede arne_v Ekspert
16. marts 2010 - 19:16 #6
Til inspiration:

using System;

namespace E
{
    public static class BirthDays
    {
        public static bool TestOneDay(DateTime testdate, DateTime birthday)
        {
            return testdate.Month == birthday.Month && testdate.Day == birthday.Day;
        }
        public static bool TestPlusMinus(DateTime testdate, DateTime birthday, int n)
        {
            for(DateTime dt = testdate.AddDays(-n); dt <= testdate.AddDays(n); dt = dt.AddDays(1))
            {
                if(TestOneDay(dt, birthday))
                {
                    return true;
                }
            }
            return false;
        }
        public static bool TestWeek(DateTime testdate, DateTime birthday)
        {
            DateTime weekstart = testdate;
            while(weekstart.DayOfWeek != DayOfWeek.Monday)
            {
                weekstart = weekstart.AddDays(-1);
            }
            for(DateTime dt = weekstart.AddDays(0); dt <= weekstart.AddDays(6); dt = dt.AddDays(1))
            {
                if(TestOneDay(dt, birthday))
                {
                    return true;
                }
            }
            return false;
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine(BirthDays.TestOneDay(DateTime.Now, new DateTime(2000, 3, 15)));
            Console.WriteLine(BirthDays.TestOneDay(DateTime.Now, new DateTime(2000, 3, 16)));
            Console.WriteLine(BirthDays.TestOneDay(DateTime.Now, new DateTime(2000, 3, 17)));
            Console.WriteLine(BirthDays.TestPlusMinus(new DateTime(2010, 1, 1), new DateTime(2002, 12, 24), 7));
            Console.WriteLine(BirthDays.TestPlusMinus(new DateTime(2010, 1, 1), new DateTime(2002, 12, 25), 7));
            Console.WriteLine(BirthDays.TestPlusMinus(new DateTime(2010, 1, 1), new DateTime(2003, 1, 1), 7));
            Console.WriteLine(BirthDays.TestPlusMinus(new DateTime(2010, 1, 1), new DateTime(2003, 1, 8), 7));
            Console.WriteLine(BirthDays.TestPlusMinus(new DateTime(2010, 1, 1), new DateTime(2003, 1, 9), 7));
            Console.WriteLine(BirthDays.TestWeek(DateTime.Now, new DateTime(2000, 3, 14)));
            Console.WriteLine(BirthDays.TestWeek(DateTime.Now, new DateTime(2000, 3, 15)));
            Console.WriteLine(BirthDays.TestWeek(DateTime.Now, new DateTime(2000, 3, 16)));
            Console.WriteLine(BirthDays.TestWeek(DateTime.Now, new DateTime(2000, 3, 21)));
            Console.WriteLine(BirthDays.TestWeek(DateTime.Now, new DateTime(2000, 3, 22)));
            Console.ReadKey();
        }
    }
}

Koden er naeppe den hurtigst mulige, men ....
Avatar billede boomshanka Nybegynder
27. marts 2010 - 09:48 #7
Jeg takker for begge indlæggere...det ser rigtig nok ikke ud til det skulle blive den hurtigste løsning, men det virker på de datoer jeg kører test på...

En stor tak til Erik og en god bunke point til arne (det virker måske letkøbt, men som sagt var jeg ved at rive hovedet af mig selv over det her problem)
Avatar billede Syska Mester
27. marts 2010 - 18:33 #8
Dette kunne også måske bruges:
DateTime dt2 = new DateTime(2010, 1, 1);
            DateTime dt1 = new DateTime(2009, 12, 31);
            long ticks = dt1.Ticks - dt2.Ticks;
            TimeSpan ts = new TimeSpan(ticks);
            Console.WriteLine(ts.ToString());

TS er jo så enten et plus eller minus tal ...

Det kan jo laves om med Math.Abs()

// ouT
Avatar billede arne_v Ekspert
27. marts 2010 - 18:44 #9
svar fra mig

performance er næppe et reelt problem - du skal bok op og checke mange millioner før at det kan måles
Avatar billede Syska Mester
27. marts 2010 - 18:46 #10
Yes ...

First make, then optimize ... :-)
Avatar billede arne_v Ekspert
27. marts 2010 - 23:16 #11
Eller måske slet ikke optimere.

Så vidt jeg kan måle så kan man teste 1-2 millioner per sekund per core.

Det er næppe umagen værd at bruge tid på at optimere.
Avatar billede Syska Mester
27. marts 2010 - 23:24 #12
Ja ... for hvem siger der er et performance problem.

mvh
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester