Olen yrittänyt laskea datediffillä kahden päivämäärän välistä eroa niin, että se antaa päivämäärien välisen ajan kuukausina eli näin kesto = DateDiff("m", alkupvm, loppupvm). Jos alkupvm on 1.1.2011 ja loppupvm 1.2.2011 funktio antaa tulokseksi 1. Mutta jos alkupvm on tuo sama ja loppupvm on 31.1.2011, funktio antaa nolla. Minä tarvitsisin fuktion, joka antaa tulokseksi yksi, vaikka loppupvm olisi 31.1.2011. Yritin lisätä dateadd-funktiolla yhden päivän jos päivä on 30 tai 31, mutta sitten tarvitsisi ottaa huomioon myös helmikuu ja karkausvuodet, joten totesin sen huonoksi ideaksi.
Miten muokkaan koodia, jotta saisin tämän onnistumaan?
Eikö tämä aikaisemmassa keskustelussa ollut kaava toimi? Jos ei suoraan, niin ei se kovin suurta muokkausta tarvinne.
Kiitos vastauksestasi Torgo. Tuo aiempi kaava antaa juuri saman vastauksen eli tapauksessa 1.1.2011-31.1.2011 se antaa 30 päivää, vaikka haluaisin, että tulokseksi tulisi yksi kuukausi. Olen yrittänyt muokata tätäkin kaavaa, mutta taitoni eivät yksinkertaisesti riitä! Onko jotain ehdotuksia, miten muokkaisin tuota kaavaa?
No, koska haluat kaavan laskevan kuukauden täydeksi, kun siitä puuttuu vielä yksi päivä, niin eikö yksinkertaisinta olisi siirtää loppupäivää yhdellä eteenpäin? Ketjussa on jo annettu kaava miten päivämäärään lisätään 6kk, joten siitä pitäisi saada helposti muokattua sopiva versio.
Minä kokeilinkin lisätä yhden päivän jos tuo toinen päivämäärä on 31. Mutta siinä tulee se ongelma, että toisissa kuukausissa on 30 päivää, jos laitan kaavaan ehdon, että lisää yhden päivän jos päivien määrä on 30, niin silloinhan se lisää sen päivän myös esim. 30.1.2011, jolloin se on väärin. Sitten on vielä helmikuu ja karkausvuosi, jotka myös pitäisi huomioida. Minulla on siis tilanne, että listassa on kaikenlaisia päivämääriä kahdessa eri sarakkeessa ja minun pitäisi laskea noiden kahden päivämäärän välinen ero kuukausissa. Tuo kaava tai datediff toimii hyvin ja oikein, jos laskee vaikka 13.1.2011-28.4.2011 välisen keston kuukausissa eli se antaa 3 kuukautta ja 15 päivää. Mutta sitten kun toisena päivämääränä on kuun viimeinen päivä, se ei anna vastaukseksi sitä yhtä kuukautta.
=DATE(YEAR(A1);MONTH(A1);DAY(A1)+1)
Hyvin tuo tuntuu lisäävän päivän riippumatta alkupäivästä.
Niin kyllä tuo lisää oikein yhden päivän, mutta kun sen ei saisi lisätä sitä kuin vain silloin kun loppupäivämääränä on kuukauden viimeinen päivä? Tämä sen takia, että kun haluan saada kahden päivämäärän välisen eron kuukausissa, niin se antaisi tilanteessa 1.1.2011-31.1.2011 tulokseksi 1 kuukautta, niin tässä tapauksessa sen pitäisi lisätä tuohon 31.1.2011 yksi päivä, jolloin tulokseksi tulisi se yksi kuukausi. Muissa tapauksissa päivämäärien välinen ero tulee kaavalla oikein. Eli nyt se kaava siinä aikaisemmassa keskustelussa antaa tällaiset vastaukset:
13.1.2011-28.4.2011 3 kuukautta 15 päivää
1.1.2011-31.1.2011 0 kuukautta 30 päivää
Eli haluaisin, että tuon viimeisen päivämäärien ero pitäisi olla 1 kuukautta 0 päivää.
Siis haluat että 1.1.2011-31.1.2011 tulokseksi tulisi 1 kk, mutta 2.1.2011-1.2.2011 tulokseksi tulisi 0 kk? Siinä tapauksessa laitat vain siihen päivän lisäykseen ehdon, että se tehdään vain jos kyseessä on kuun viimeinen päivä. Tarkistuksen voi tehdä tuhannella tapaa. Itselle ensimmäisenä tuli mieleen että päivän lisääminen tehdään, jos se vaihtaa samalla kuukautta. Googlella löytyy varmasti helpompiakin tapoja.
Edit.
Tässä vielä tuo oma ajatukseni pikaisesti kyhättynä. Siistimpiäkin tapoja varmasti on, mutta ainakin tämä toimi kun testasin:
=IF(MONTH(DATE(YEAR(A1);MONTH(A1);DAY(A1)+1))<>MONTH(A1);DATE(YEAR(A1);MONTH(A1);DAY(A1)+1);A1)
Moi Mamma!
oheinen funktio palauttaa annetusta päivämäärästä kuukauden viimeisen päivän...
Private Function LastOfMonth(pDate As Date) As Integer Select Case Month (pDate) Case 1, 3, 5, 7, 8, 10, 12 LastOfMonth = 31 Case 4, 6, 9, 11 LastOfMonth = 30 Case 2 If (Year(pDate) Mod 4) = 0 Then LastOfMonth = 29 Else LastOfMonth = 28 End If End Select End Function Private Sub Command1_Click() 'testi... Dim Date1 As Date, Date2 As Date Date1 = "1.2.2011": Date2 = "28-2-2011" If Year(Date1) = Year(Date1) And Month(Date1) = Month(Date2) _ And Day(Date1) = 1 And Day(Date2) = LastOfMonth(Date2) Then MsgBox ("1 kuukausi") ElseIf Year(Date1) = Year(Date1) And Month(Date1) = Month(Date2) _ And Day(Date1) = 1 And Day(Date2) < LastOfMonth(Date2) Then MsgBox DateDiff("d", Date1, Date2) & " päivää" 'ElseIf '.... '... Else '... End If End Sub
Pari korjausta neau33:n koodiin:
Karkausvuosi on joka neljäs vuosi PAITSI jos vuosi on jaollinen 400lla.
Toiseksi, miksi koodi tarkistaa Year(Date1) = Year(Date1)?
MOI taas!
Henkka@
Year(Date1) = Year(Date1) copy/paste failuresta huolimatta toi funkkari palauttaa annetun päivämäärän kuukauden viimeisen päivän ainakin seuraavat 1000 vuotta mikäli käyttis sallii...
Ota ero päivinä ja pyöristä...
Äh, kirjoitin ennen kuin ajattelin, sorry.
Ongelman voisi kyllä määritellä vielä selvemmin. Onko tosiaan tarkoitus, että kuukauden ensimmäisestä päivästä viimeiseen on yksi kuukausi (esim. siis helmikussa 28 päivää mutta tammikuussa 31 päivää)? Silloinhan ongelma ratkeaa niin, että loppupäivämäärään lisätään aina yksi päivä. Kuitenkin ratkaisu vaikuttaa aika typerältä, koska sama määrä päiviä voi tuottaa eri määrän kuukausia.
Hennkka ja neau33 ovat molemmat väärässä karkausvuoden suhteen. 400:llä jaolliset ovat, muut 100:lla jaolliset eivät, loput 4:llä jaolliset ovat. Siispä neau33:n koodi toimisi vain vuoteen 2099 asti, koska vuoden 2100 ei kuulu olla karkausvuosi.
Niinpä onkin. Ei pitäisi yrittää vastata ulkomuistista asioihin, joista ei ole itsekkään varma. Täytyy varmaan vierittää syy puhelimen niskoille, koska ei voinut tarkistaa Wikipediasta:D
Kiitos kaikille vastauksista. Kuten Metabolix sanoi, se vaikuttaa typerältä, että lisätään jokaiseen kuukauden viimeiseen päivään yksi päivä, jotta datediff antaisi vastauksen yksi kuukausi. Tässä tapauksessahan pitäisi tosiaankin ottaa huomioon kaikkien kuukausien päivien määrät ja karkausvuodet. On kyllä aika kummallista, että Excelissä ei ole valmiina sellaista funktiota, joka antaisi tulokseksi yhden kuukauden, jos ensimmäinen päivämäärä on kuun ensimmäinen päivä ja toinen kuun viimeinen päivä. Oikeastaanhan noiden kahden päivämäärän välinen ero on vain esim. 30 päivää, jos päivämääräväli on 1.1.2011-31.1.2011. Mutta jos ajatellaan vaikka työsuhteen kestoa, niin kyllä silloin lasketaan työsuhteen pituuteen myös tuo viimeinenkin päivä eli työsuhteen pituus on yksi kuukausi. Jos laskee datediffillä esim. 1.1.2011-16.1.2011, se antaa tulokseksi 15 päivää, vaikka jos taas ajatellaan esim. työsuhteen kestoa, niin silloin pitäisi kestoksi tulla 16 päivää. Eli näissäkin tapauksissa pitäisi lisätä yksi päivä tuohon loppupäivämäärään. Ei kai tässä ole muuta vaihtoehtoa, kuin koodata niin, että kaikkiin loppupäivämääriin lisätään yksi päivä ja sen jälkeen vasta vähennetään loppupäivästä alkupäivä?
Function Kesto(ByVal AloitusPvm As Date, ByVal LopetusPvm As Date) As String Dim Vuodet As Integer, Kuukaudet As Integer, Paivat As Integer Dim PaiviaKuukaudessa As Integer Vuodet = DateDiff("y", AloitusPvm, LopetusPvm) AloitusPvm = DateAdd("y", Vuodet, AloitusPvm) Kuukaudet = DateDiff("m", AloitusPvm, LopetusPvm) AloitusPvm = DateAdd("m", Kuukaudet, AloitusPvm) Paivat = DateDiff("d", AloitusPvm, LopetusPvm) + 1 PaiviaKuukaudessa = Day(DateSerial(Year(AloitusPvm), Month(AloitusPvm) + 1, 0)) If Paivat >= PaiviaKuukaudessa Then Kuukaudet = Kuukaudet + 1 Paivat = Paivat - PaiviaKuukaudessa End If If Vuodet > 0 Then Kesto = Vuodet & " vuotta" If Kuukaudet > 0 Then If LenB(Kesto) <> 0 Then Kesto = Kesto & ", " Kesto = Kesto & Kuukaudet & " kuukautta" End If If Paivat Then If LenB(Kesto) <> 0 Then Kesto = Kesto & ", " Kesto = Kesto & Paivat & " päivää" End If End Function
Testaamaton.
Entäs siten että otetaan kaksi vastausta ja valitaan niistä isompi.
Eka normaalisi, toinen siten että lisätään molempiin päivämääriin yksi.
Laitetaan tässä nyt eri päivän kahvitauolla sitten, että miten tuo edellisen viestini koodi toimii.
Yksinkertaisin kohta on vuosien ja kuukausien laskeminen, aloituspäivämäärään lisätään DateDiffin ilmoittama ero. DateDiff ilmoittaa muistaakseni vain täysin kokonaiset vuodet ja kuukaudet, joten tällä tavoin kasvattamalla AloitusPvm:ää jää jäljelle ensin vain kuukaudet ja sitten lopulta päivät.
Lopulta sama tehdään myös päiville, mutta lisätään aina yksi. Tämän jälkeen katsotaan montako päivää on viimeisessä kuukaudessa, joka aloituspäivämäärän kohdalle osuu. Jos lukema on kuukauden päivien määrä tai tätä isompi, niin kuukausien määrää kasvatetaan yhdellä ja vastaavasti päivien määrä pienenee kuukauden päivien määrällä.
Aikavälin 1.1.2011 - 1.2.2011 pitäisi siis antaa vastaukseksi "1 kuukautta, 1 päivää"
Karkausvuosia ym. ei tarvitse ottaa huomioon, koska VB:n päivämääräfunktioita käyttäen nämä asiat otetaan huomioon taustalla automaagisesti (olettaen että siellä ei ole bugeja).
Nyt kokeilin tuota Merrin koodia, mutta se antaa aikavälin 1.1.2011-1.2.2011 vastaukseksi 31 vuotta 1 päivää. Yritin korjata koodia, mutta en oikein osannut?
"y" tilalle "yyyy"
"y" ilmoittaakin näemmä päivän vuoden järjestysnumeron. Sen takia tulee 31 vuotta.
Kiitos kovasti Merri, nyt koodi toimii kuin unelma! Kiitos myös itse koodista, nyt pääsen eteenpäin hommassani!
Nyt vielä testasin ja koodi antaa ajalle 1.1.2009-1.1.2010 tulokseksi 1 vuotta ja 1 päivää. Eli tuo vuoden vaihtuminen nyt jotenkin sekoittaa. Minä olen niin alussa tämän koodin kanssa, että en osaa korjata tätä?
Eikös se toimi kuten pitääkin? 1.1.2009-31.12.2009 pitäisi olla 1 vuosi, jolloin 1.1.2009-1.1.2010 pitäisikin olla 1 vuosi ja 1 päivä. Vai ymmärsinkö jotain väärin?
Niin, 6.6. - 7.6. on 2 päivää, mutta päivien 6.6. ja 7.6. välinen ero on 1 päivä. Eli jos tässä nyt eroa kysytään niin 1.1.2009 vs 1.1.2010 on tasan 1 vuosi.
Eli ongelmahan poistuu, kun poistaa tämän rivin lopussa olevan +1:
Paivat = DateDiff("d", AloitusPvm, LopetusPvm) + 1
Minä laitoin äsken väärän esimerkin eli se on mun mielestä oikein, mutta sitten kun laittaa välin 1.12.2009-31.1.2010 koodi antaa tulokseksi 1 vuotta. Tuon aikavälin erotushan on 2 kuukautta?
Hmm, jos DateDiffin vuosilaskuri antaa vastaukseksi 1 kun vuosilukema poikkeaa, niin sitten tuo koodi ei ymmärrettävästi toimi. Ei ole VB6 asennettuna, niin on testaaminen vähän heikossa.
Tuon ongelman ratkominen muuttuu vähän ongelmallisemmaksi, eli pitäisi tarkistaa ensin vuoden päivien määrä, verrata sitä päivien erotukseen vuosien välillä ja sitten vasta tietää, onko Vuodet
tuossa tapauksessa 1 vai 0.
Niin, 1 vuosi, -10 kuukautta ja 2 päivää. Mutta toi ei näytä negatiivisia kuukausia.
Mites tällainen suht perverssin näköinen koodi:
(Tämähän piti kai olla Excelin VBA eikä VB6:ssa? Testattu Excelissä)
Function Kesto(ByVal AloitusPvm As Date, ByVal LopetusPvm As Date) As String Dim Vuodet As Integer, Kuukaudet As Integer, Paivat As Integer Dim Vu As Integer, Kk As Integer, Pv As Integer LopetusPvm = LopetusPvm +1 'Halutaan laskea sekä alku- että loppupäivä mukaan Vu = Year(AloitusPvm): Kk = Month(AloitusPvm): Pv = Day(AloitusPvm) Vuodet = Year(LopetusPvm) - Vu Kuukaudet = Month(LopetusPvm) - Kk If DateSerial(Vu + Vuodet, Kk, Pv) > LopetusPvm Then Vuodet = Vuodet - 1 Kuukaudet = Kuukaudet + 12 End If If DateSerial(Vu + Vuodet, Kk + Kuukaudet, Pv) > LopetusPvm Then Kuukaudet = Kuukaudet - 1 Paivat = LopetusPvm - DateSerial(Vu + Vuodet, Kk + Kuukaudet, Pv) If Vuodet > 0 Then Kesto = Vuodet & " vuotta" If Kuukaudet > 0 Then If LenB(Kesto) <> 0 Then Kesto = Kesto & ", " Kesto = Kesto & Kuukaudet & " kuukautta" End If If Paivat Then If LenB(Kesto) <> 0 Then Kesto = Kesto & ", " Kesto = Kesto & Paivat & " päivää" End If End Function
Eikös VB6:ssa ole mukana funktioita, joilla päivämäärän voisi muuttaa Lilian days muotoon ja siitä takaisin normaaliin päiväykseen?
Eli siis muotoon, joka esittää päivämäärään päivinä Gregoriaanisen kalenterin alusta.
Meinaan vaan, että tuosta saisi kivat luvut, joilla on helppo laskea kulunutta aikaa.
PL/I:llä ohjelmoidessa, näin nopeasti mietittynä lähtisin varmaan tuosta lähtökohdasta liikkeelle...
-jalski
Joo. Tuohon muotoon voi muuttaa funktiolla int() ja takaisin cdate(). Tai no, alkupäivänä on 1.1.1900 ja negatiiviset siitä taakse päin. En vaan hahmota miten olisi hyötyä koodata oma kalenteri, kun se on valmiinakin.
Grez: VBA ja VB6 on melkein sama asia perusfunktioiden kirjoittamisen kannalta :)
Mamma kirjoitti:
Ei kai tässä ole muuta vaihtoehtoa, kuin koodata niin, että kaikkiin loppupäivämääriin lisätään yksi päivä ja sen jälkeen vasta vähennetään loppupäivästä alkupäivä?
Jos se kelpaa ratkaisuksi, niin sitten tuo alunperinkin ehdottamani Excel-kaava edellisestä ketjusta toimii oikein. Testailin Excel 2007:lla ja kaikki tässä ketjussa esitetyt esimerkkitapaukset toimii oikein.
Merri kirjoitti:
Grez: VBA ja VB6 on melkein sama asia perusfunktioiden kirjoittamisen kannalta :)
Tiedän. Tuo oli lähinnä kommentiksi sinulle:
Merri kirjoitti:
Ei ole VB6 asennettuna, niin on testaaminen vähän heikossa.
Ehkä tarkoitit sanoa ettei ole myöskään Exceliä asennettuna. Aloittaja kuitenkin ilmeisesti käyttää Exceliä, joten en ymmärtänyt miksi se ehdoin tahdoin VB6:ssa pitäisi testata.
Aihe on jo aika vanha, joten et voi enää vastata siihen.