[C] datums vergelijken

Pagina: 1
Acties:

  • LittleWan
  • Registratie: Februari 2003
  • Laatst online: 13-03 18:21
hoi,
ik wist niet dat het zo moelijk was, maar ik moet voor een programma voor een µC in "C" een datum vergelijken om te kijken of deze binnen een bepaalde periode zit. De getallen worden als bcd in het programma gebruikt (0x12 wil zeggen dag 12) dit maakt niets uit voor de vergelijking dacht ik.
ik heb al vanalles geprobeerd, flowcharts, alles appart uitrekenen,....
iemand een idee hoe ik dit het beste aanpak??

Ik heb dus volgende gegevens:
datum 1: JAR = 05h, MND = 03h, DAG = 01h
vandaag: JAR = 05h, MND = 03h, DAG = 29h
datum 2: JAR = 05h, MND = 04h, DAG = 01h

ik wil gewoon weten of vandaag tussen die 2 datums valt of niet.
ik heb al geprobeerd volgens de - x < y < z - manier proberen werken maar dit lukt niet :s

http://www.sillevl.be - blog http://www.sillevl.be/blog - flickr http://www.flickr.com/sillevl


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Heb je x<y werkend? Dan komt x<y<z vanzelf.
Zoniet, leg dan uit waarom J=5,M=3,D=1 < J=5,M=3,D=29

(Het klopt dat BCD de gewone < relatie in stand houdt)

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Daos
  • Registratie: Oktober 2004
  • Niet online
x < y && y < z

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19:34

MBV

Heb je geen library om datums te vergelijken? Zonee: zoek eens op functies die dat doen, zijn vast en zeker open source alternatieven voor te bedenken.
Ik ben bang dat ik nu te simpel denk, dus probeer mijn redenatie eerst uit op de randgevallen!

stel je voor, een datum is in feite een X aantal dagen vanaf het jaar 0 in een ingewikkeld formaat. Als je dat formaat een beetje versimpelt, kan je al data vergelijken:
code:
1
approximateDaysFromZero = Years * 365 + Months * 31 + Days * 1

Gevolg is dat je een getalletje hebt dat je eenvoudig kan vergelijken.
Mijn redenatie hierachter: de dagen die je moet overslaan (om de maand, februari etc) komen toch niet voor. Je wilt alleen weten of 28 februari tussen 27 februari en 1 maart ligt. 30 februari is geen geldige datum, en je preconditie zal zijn dat je een geldige datum krijgt.

Ook zou je een functie kunnen maken:
code:
1
2
3
4
5
6
7
8
9
bool date_IsGreaterThan(xDay, xMonth, xYear, yDay, yMonth, yYear)
{
  if (xYear > yYear && xMonth > yMonth && xDay > yDay) {
    return true;
  } 
  else{
    return false;
  }
}

Deze moet je wel een beetje aanpassen natuurlijk, 'k zat even niet na te denken. De volgende hoef je alleen te vergelijken als de vorige gelijk is, maar dat is teveel typen :P
alsjeblieft voor je huiswerk :P

[ Voor 9% gewijzigd door MBV op 30-03-2005 22:04 ]


  • DRAFTER86
  • Registratie: April 2002
  • Laatst online: 22:25
Je bent je er van bewust dat 12 hexadecimaal niet hetzelfde is als 12 decimaal?

  • Daos
  • Registratie: Oktober 2004
  • Niet online
DRAFTER86 schreef op woensdag 30 maart 2005 @ 23:27:
Je bent je er van bewust dat 12 hexadecimaal niet hetzelfde is als 12 decimaal?
In Binary-coded decimal (BCD) codering is dat hetzelfde.


Implementatie kan bijvoorbeeld zo:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <string.h>
#include <stdio.h>

int main() {
    char d1[] = {5, 3, 1};
    char v[] = {5, 3, 0x29};
    char d2[] = {5, 4, 1};

    if (strncmp(d1, v, 3) <= 0 && strncmp(v, d2, 3) <= 0)
        printf("zit er tussen\n");
    else
        printf("zit er niet tussen\n");


    return 0;
}

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23:16
Anders maak je van je datum een getal en vergelijk je die

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Daos schreef op woensdag 30 maart 2005 @ 23:51:
[...]
In Binary-coded decimal (BCD) codering is [12hex] hetzelfde [als 12 dec].
Niet in deze context. 12 decimaal * 31 = 372, 12 hex * 31 = 18*31 = 558.
Je ziet overigens al dat je het jaar niet met 365 moet vermenigvuldigen.
Anders is 1-1-02 < 31-12-01 ( 762 < 768 )

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19:34

MBV

volgens mij maakt dat geen bal uit, aangezien je waardes gaat vergelijken. Je zal wel moeten oppassen dat je geen waarde kan krijgen die groter is dan int mag hebben. Ik had het duidelijker kunnen maken door jaar*10000, maand*100 en dag*1 te doen. Effect is hetzelfde: als de som voor waarde 1 groter is dan voor 2, is hij later. dus kan je vergelijken :)
offtopic:
misschien win ik het dit keer wel van MSalters :P

[ Voor 10% gewijzigd door MBV op 31-03-2005 10:31 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 09-05 04:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je originele voorbeeld was fout, want er worden BCD's gebruikt, die bovendien bij 1 beginnen te tellen. Je moet altijd zorgen dat een verhoging van het volgende significante getal in totaal meer is dan de maximale verhoging van het significante getal dat ervoor komt. Met andere woorden, je moet jaren niet vermenigvuldigen met 365 omdat 31 december, oftewel 12 * 31 + 31, meer is dan 365 (en dus meer is dan een jaar, wat niet waar is). En daarnaast zijn het ook nog eens BCD's, dus heeft een maand meer dan 31 dagen (namelijk 31h = 49 dagen).

Dus helaas, je gaat het niet winnen van MSalters ;)

Aangezien het toch al BCD's zijn kun je ze ook gewoon in een 32 bits int shiften, waarbij je 8 bits gebruikt voor maanden en dagen en 16 bits voor de jaren

C:
1
2
3
4
5
6
7
int datumWaarde1 = jaar1 << 16 | maand1 << 8 | dag1;
int datumWaarde2 = jaar2 << 16 | maand2 << 8 | dag2;

if (datumWaarde1 < datumWaarde2)
    printf ("datum1 is kleiner dan datum2\n");
else
    printf ("datum1 is groter dan of gelijk aan datum2\n");

[ Voor 32% gewijzigd door .oisyn op 31-03-2005 11:11 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Overigens moet je niet met multipliers (of shifts, dat is hetzelfde) gaan werken. De TS is student, die moet gewoon leren om een vergelijking op meerdere velden te maken. Vergelijken op 3 strings heeft hetzelfde probleem, en daar werkt vermenigvuldigen ook niet. Leren is dus het doel, en niet een eindproduct.

[ Voor 16% gewijzigd door MSalters op 31-03-2005 11:11 ]

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • LittleWan
  • Registratie: Februari 2003
  • Laatst online: 13-03 18:21
ik heb alle manieren hier voorgesteld uitgeprobeerd (moet zeggen dat ik die manier ook al geprobeerd had door elk een weging mee te geven en dat in 1 int te steken, echter denk ik dat ik hiermee vaak een overflow veroorzaak :s)
ik beschik niet over de string library dus stringvergelijking is uitgesloten.
Bij ELKE manier die ik probeer kom ik tot volgende conclusie dat het niet werkt, als ik een datum at random neem is het resultaat van die vergelijking even random, ik kan er ook geen patroon in vinden die me duidelijk maakt van dan niet en dan wel. Wel heb ik de indruk dat de maanden de belanrijkste doorslag hebben op het resultaat (het is net of de dagen en jaren niet meegerekend worden)... :s heel raar allemaal vind ik maar

http://www.sillevl.be - blog http://www.sillevl.be/blog - flickr http://www.flickr.com/sillevl


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Geloof ons: elke manier die hier genoemd is werkt, met uitzondering van de eerste poging van MBV. Als het toch niet werkt, dan doe je niet wat wij zeggen. Kan er niks anders van maken.

Overigens is een int tenminste 15 bits, unsigned zelfs 16. Aangezien een maan minder dan 1<<5 dagen heeft, en een jaar minder dan 1<<4 maanden, kun je vrij eenvouding 1<<7 jaar kwijt in een unsigned, maar dan moet je terugrekenen van bcd naar binair. Anders kun je een long gebruiken, daar passen altijd je 3 bytes in.

[ Voor 4% gewijzigd door MSalters op 31-03-2005 18:45 ]

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • LittleWan
  • Registratie: Februari 2003
  • Laatst online: 13-03 18:21
ik ben er ook van overtuigd dat alle manieren dat jullie zeggen ook werken, als je een beetje logisch redeneerd zie je dat vlug. Net omdat ik weet dat het werkt in theorie ergert het mij nog eens zo hard dat het praktisch niet wil werken :s
*zucht*
:'(

http://www.sillevl.be - blog http://www.sillevl.be/blog - flickr http://www.flickr.com/sillevl


  • riezebosch
  • Registratie: Oktober 2001
  • Laatst online: 04-05 13:09
En als je 'm nou omzet naar een getal yyyymmdd? Dan kan je toch gewoon vergelijken of 20050331 tussen 20050330 en 20050401 ligt? :)

edit:

(yyyy * 10000) + (mm * 100) + (dd)

[ Voor 18% gewijzigd door riezebosch op 31-03-2005 19:33 ]

Canon EOS 400D + 18-55mm F3.5-5.6 + 50mm F1.8 II + 24-105 F4L + 430EX Speedlite + Crumpler Pretty Boy Back Pack


  • LittleWan
  • Registratie: Februari 2003
  • Laatst online: 13-03 18:21
riezebosch schreef op donderdag 31 maart 2005 @ 19:31:
En als je 'm nou omzet naar een getal yyyymmdd? Dan kan je toch gewoon vergelijken of 20050331 tussen 20050330 en 20050401 ligt? :)
Heb ik al geprobeerd werkt ook niet.
Ik denk dat ik geen int kan gebruiken die dat bereik aan kan :s

http://www.sillevl.be - blog http://www.sillevl.be/blog - flickr http://www.flickr.com/sillevl


  • Werkbouwtuig
  • Registratie: Juli 2003
  • Niet online
Volgens mij haal de dat makkelijk met een unsigned long (int) , aangezien datums toch niet negatief kunnen worden in deze notatie.

Het volgende is enigsinds systeem / compiler afhankelijk en kan je vinden in limits.h, ik heb er even de waardes van mijn compiler bijgezet.

unsigned long loopt van 0 tot 0xFFFFFFFF (4294967295 decimaal) (0 ULONG_MAX)
long int loop van -2147483646 tot 2147483647 (LONG_MIN LONG_MAX)

[ Voor 54% gewijzigd door Werkbouwtuig op 31-03-2005 21:20 ]


Verwijderd

was dat niet simpel met JulianDate
weet alleen niet meer of dat standaard in ansi C zit ....
dagnummer vanaf 1-1-1900 = 0 , 2-1-1900 = 1 en zo verder
maar ik zie zat sources als ik naar juliandate zoek ;-)

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Julian date vanaf BCD is lastig. Naar 0x20050401 of 0x050401 is simpel, en dat past altijd in een long.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • LittleWan
  • Registratie: Februari 2003
  • Laatst online: 13-03 18:21
ik ga dit even stil leggen en volgende week ga ik op mijn stageplaats eens met de debugger werken daar kan ik dan mooi in zien waar het fout gaat. Debuggen via de display is lastig nu omdat ik niets heb om int op de display te plaatsen, en dat zelf maken zou te lang duren denkik.
alvast bedankt, ik hou jullie op de hoogte, en als jullie nog een ide hebben laat het maar weten

http://www.sillevl.be - blog http://www.sillevl.be/blog - flickr http://www.flickr.com/sillevl


Verwijderd

VB code om datum om te zetten naar JD
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Public Function JulianDay(Years As Single, Months As Integer, Days As Single) As Double
   On Error GoTo JulianErr
   'Functie berekent de julianse dag voor de aangegeven datum
   'waarbij de variable Days in decimale dagen opgegeven hoort
   'te worden.
   'ALLEEN VOOR DATA TUSSEN 1 MAART 1900 EN 28 FEBRUARI 2100
   'Anders functie aanpassen!!!
   Dim A As Integer
   Dim B As Integer
   
   If Years < 1901 Or Years > 2099 Then
      JulianDay = -1
   Else
      If Months = 1 Or Months = 2 Then
         'Beschouw Januari en Februari als 13e en 14e maand van vorig jaar!!
         Years = Years - 1
         Months = Months + 12
      End If
   
      A = Int(Years / 100)
      B = -13
   
      JulianDay = CDbl(Int(365.25 * (Years + 4716)) + Int(30.6001 _
         * (Months + 1)) + Days + B - 1524.5)
   End If
   Exit Function
JulianErr:
   Err.Clear
   JulianDay = 0
End Function

Als je de datum om heb gezet naar JD kun je verschillen berekenen door data van elkaar af te trekken. Ik hoop dat je er iets aan hebt :)
De formules heb ik uit:
Astronomical Algorithms van Jean Meeus

Code komt uit Stars:
http://home.planet.nl/~romme102/

[ Voor 5% gewijzigd door Verwijderd op 31-03-2005 22:02 ]


  • Elijan9
  • Registratie: Februari 2004
  • Laatst online: 02-05 13:12
MBV schreef op woensdag 30 maart 2005 @ 22:03:
Ook zou je een functie kunnen maken:
[...]
Deze moet je wel een beetje aanpassen natuurlijk, 'k zat even niet na te denken. De volgende hoef je alleen te vergelijken als de vorige gelijk is, maar dat is teveel typen :P
alsjeblieft voor je huiswerk :P
"Beter geen voorbeeld, dan een slecht voorbeeld"?

ik zou iets doen als:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int date_compare_less(date_t lhs, date_t rhs )
{
    if (lhs.year == rhs.year)
    {
        if (lhs.month == rhs.month)
        {
            return lhs.day < rhs.day;
        }
        else
            return lhs.month < rhs.month;
    }
    else
        return lhs.year < rhs.year;
}


Volgens mij kun je die vergelijking gewoon direct als BCD al doen, ik zie niet staan dat het een eis is om ook te weten hoeveel dagen je bent verwijderd van een andere datum.

[ Voor 45% gewijzigd door Elijan9 op 01-04-2005 16:54 . Reden: wrong button (i.p.v. preview submit ) ]

War is when the young and stupid are tricked by the old and bitter into killing each other. - Niko Bellic


  • LittleWan
  • Registratie: Februari 2003
  • Laatst online: 13-03 18:21
GOED NIEUWS !!!
Het werkt. Ik heb het op de methode van Elijan9 gedaan en die werkt perfect ! thx Eluian9
Elijan9 schreef op vrijdag 01 april 2005 @ 09:41:
[...]
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int date_compare_less(date_t lhs, date_t rhs )
{
    if (lhs.year == rhs.year)
    {
        if (lhs.month == rhs.month)
        {
            return lhs.day < rhs.day;
        }
        else
            return lhs.month < rhs.month;
    }
    else
        return lhs.year < rhs.year;
}


Ik vind het jammer dat ik zoveel tijd verloren ben hiermee. Ik vind het dom van me dat ik niet eerder inzag dat deze methode NIET werkt
MBV schreef op woensdag 30 maart 2005 @ 22:03:
code:
1
2
3
4
5
6
7
8
9
bool date_IsGreaterThan(xDay, xMonth, xYear, yDay, yMonth, yYear)
{
  if (xYear > yYear && xMonth > yMonth && xDay > yDay) {
    return true;
  } 
  else{
    return false;
  }
}
wanneer de jaren bijvoorbeeld een true opleveren kunnen de dagen nog een false opleveren met als gevolg dat de hele vergelijking false wordt maar dit niet zo is. De jaren hebben een grotere wegingsfactor die met deze formule niet in rekening gebracht wordt. Je vergelijkt dus 3 afzonderlijke getallen en het resultaat is enkel true als alle afzonderlijke getallen groter zijn :s

Hier heb ik te lang mee bezig geweest tot ik het doorzag :s jammer.


Ik vraag me nog altijd af waarom de methode met het omvormen naar een int niet werkte :s Ik heb geen tijd meer om dit nog eens uit te testen, ik ga nu lekker verder programmeren aan mn mp3speler
Iedereen hartelijk bedankt !!!

http://www.sillevl.be - blog http://www.sillevl.be/blog - flickr http://www.flickr.com/sillevl


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19:34

MBV

Ik had het er zelf nog onder gezet dat die manier niet werkte. Ik was toen alleen een beetje moe etc, kon het ff niet opbrengen om het zelf uit te tikken. De beschrijving eronder klopte dus wel :P
Sorry voor de onduidelijke uitleg

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
LittleWan schreef op maandag 04 april 2005 @ 15:50:
GOED NIEUWS !!!
Het werkt. Ik heb het op de methode van Elijan9 gedaan en die werkt perfect ! thx Eluian9
Maar snap je het nou ook? Kun je nu een struct persoon sorteren op persoon.achternaam, persoon.voornaam en persoon.geboortedatum?

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 19:34

MBV

lijkt mij een vraag die zijn leraar mag stellen, denk je niet? :P Zeker als zijn leraar dit topic vindt :)
[offtopic]idd, het staat nergens. Het klinkt als een proof-of-concept dat voor een electro- of informaticastudie bedacht had kunnen zijn. 'k moet eens wat minder snel oordelen :) [/edit]

[ Voor 47% gewijzigd door MBV op 06-04-2005 23:46 ]


  • Elijan9
  • Registratie: Februari 2004
  • Laatst online: 02-05 13:12
MSalters schreef op maandag 04 april 2005 @ 22:36:
[...]

Maar snap je het nou ook? Kun je nu een struct persoon sorteren op persoon.achternaam, persoon.voornaam en persoon.geboortedatum?
Blijkbaar wel als je zijn verhaal ook verder leest... Dan heeft hij het juist heel goed begrepen.
Als .oisyn zijn methode ook had gewerkt, dan weet ik niet of de TS het wel had begrepen...

@.oisyn: Niet zo voor de hand liggend om er blind van uit te gaan dat de grootte voor een int bij een onbekende microcontroller met willekeurige compiler wel 32 bit zal zijn... :?

offtopic:
Ik lees nergens dat het hier om een schoolopdracht ging hoor... Ik "moet" ook wel eens iets voor elkaar krijgen, zonder dat iemand mij daarvoor de opdracht heeft gegeven.

War is when the young and stupid are tricked by the old and bitter into killing each other. - Niko Bellic

Pagina: 1