Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: VB6: VB: Työajan jako (yö, päivä, ilta)

Sivun loppuun

Tiedonhaluinen [10.05.2017 12:07:51]

#

Visual Basic: Työajan jakaminen Yö-, Päivä-, Iltavuoro

Minulla on ohjemapätkä jossa:
StartTime ja EndTime.

Kokonaistunnit otan lauseesta:
Kokonaistunnit = DateDiff("s", txtStartTime, txtEndTime) / 60 / 60
(tarvitsen sekunnin osat myös).

Esim. työntekijä 1 aloittaa työt 20.04.2017 19:57:19 ja lopettaa 21.04.2017 21:35:42

Nyt näistä tiedoista tarvitsisi saada tehdyt vuorotunnit:
Yötunnit (aikaväli #00:00:00# - #06:00:00#)
Päivätunnit (aikaväli #06:00:00# - #18:00:00#)
Iltatunnit (aikaväli #18:00:00# - #24:00:00#)

Grez [10.05.2017 18:06:08]

#

Löytyisikö vanhasta keskustelusta jotain vinkkejä?
https://www.ohjelmointiputka.net/keskustelu/28439-ajan-pilkkominen

jalski [11.05.2017 09:59:21]

#

Itse kirjoittelisin jonkunlaiset funktiot bittimerkkijonojen käsittelyä varten, joissa olisi riittävä toiminnallisuus tätä tehtävää varten.

Jännä muuten, miten moni nykypäivän kieli ei bittimerkkijonoja suoraan tue vaikka nämä helpottaisivat suuresti erilaisten joukkojen käsittelyä.

Alla PL/I toteutus, saako joku toteutettua helpommin?

*PROCESS MARGINS(1,180) LIBS(SINGLE,STATIC);
*PROCESS OPTIMIZE(2) DFT(REORDER);


 test: proc options(main);

    dcl nightmask bit(24)   init('111111000000000000000000'b);
    dcl eveningmask bit(24) init('000000000000000000111111'b);
    dcl daymask bit(24)     init('000000111111111111000000'b);

    dcl hourmask bit(24);

    dcl result bit(24);

    dcl seconds fixed decimal(15,0);

    dcl (started, ended) char (19);

    dcl 1 worktime,
          2 hours pic'99',
          2 * char(1) init(':'),
          2 minutes pic'99',
          2 * char(1) init(':'),
          2 seconds pic'99';


    /* Aikaleimat */
    started = '20.04.2017 05:35:01';
    ended   = '20.04.2017 20:47:10';

    /* tehdyt tunnit */
    hourmask = copy('0'b, substr(started,  12, 2)) || copy('1'b, substr(ended,  12, 2)-substr(started,  12, 2));

    /* Päivätunnit */
    result = hourmask & daymask;
    seconds = (tally(result, '1'b)) * 3600;
    if substr(daymask, wrap(substr(started, 12, 2)+1), 1) = '1'b then seconds -= substr(started, 15, 2) * 60 + substr(started, 18, 2);
    if substr(daymask, wrap(substr(ended, 12, 2)+1), 1) = '1'b then seconds += substr(ended, 15, 2) * 60 + substr(ended,  18, 2);

    worktime.hours = seconds/3600;
    worktime.minutes = mod(seconds, 3600)/60;
    worktime.seconds = mod(seconds, 60);
    put skip list('Day time    : ' || string(worktime));

    /* Iltatunnit */
    result = hourmask & eveningmask;
    seconds = (tally(result, '1'b)) * 3600;
    if substr(eveningmask, wrap(substr(started, 12, 2)+1), 1) = '1'b then seconds -= substr(started, 15, 2) * 60 + substr(started, 18, 2);
    if substr(eveningmask, wrap(substr(ended, 12, 2)+1), 1) = '1'b then seconds += substr(ended, 15, 2) * 60 + substr(ended,  18, 2);

    worktime.hours = seconds/3600;
    worktime.minutes = mod(seconds, 3600)/60;
    worktime.seconds = mod(seconds, 60);
    put skip list('Evening time: ' || string(worktime));

    /* Yötunnit */
    result = hourmask & nightmask;
    seconds = (tally(result, '1'b)) * 3600;
    if substr(nightmask, wrap(substr(started, 12, 2)+1), 1) = '1'b then seconds -= substr(started, 15, 2) * 60 + substr(started, 18, 2);
    if substr(nightmask, wrap(substr(ended, 12, 2)+1), 1) = '1'b then seconds += substr(ended, 15, 2) * 60 + substr(ended, 18, 2);

    worktime.hours = seconds/3600;
    worktime.minutes = mod(seconds, 3600)/60;
    worktime.seconds = mod(seconds, 60);
    put skip list('Night time  : ' || string(worktime));


       wrap: proc(x) returns(fixed bin(31));
          dcl x fixed bin(31);

          if x < 1 | x > 24 then
             x = 1;

          return(x);

       end wrap;

 end test;

jalski [14.05.2017 11:24:39]

#

Pistetään vielä HotBasic versio, minkä pohjalta Visual Basic version tekeminen ei tuottane ongelmia:

$APPTYPE CONSOLE: $TYPECHECK ON

type TIMEFIELD
	hours as long
	minutes as long
	seconds as long
end TIMEFIELD

declare function calc(mask as string) as long
declare function wrap(x as long) as long

dim started as TIMEFIELD, ended as TIMEFIELD

defstr nightmask    = "111111000000000000000000"
defstr eveningmask 	= "000000000000000000111111"
defstr daymask 		= "000000111111111111000000"

defstr hourmask

deflng seconds


' Aseta työaika
started.hours = 05
started.minutes = 35
started.seconds = 01

ended.hours = 20
ended.minutes = 47
ended.seconds = 10

' Rakenna maski tehdyille tunneille
hourmask = string$(started.hours, "0")
hourmask.append string$(ended.hours - started.hours, "1")
hourmask.append string$(24 - hourmask.len, "0")

' Päivätunnit
seconds = calc(daymask)
print "day hours:"
print str$(seconds \ 3600)+ ":" + str$((seconds mod 3600) \ 60)+ ":"  + str$(seconds mod 60) + crlf

' Iltatunnit
seconds = calc(eveningmask)
print "evening hours:"
print str$(seconds \ 3600)+ ":" + str$((seconds mod 3600) \ 60)+ ":"  + str$(seconds mod 60) + crlf

' Yötunnit
seconds = calc(nightmask)
print "night hours:"
print str$(seconds \ 3600)+ ":" + str$((seconds mod 3600) \ 60)+ ":"  + str$(seconds mod 60) + crlf

pause
end


function calc(mask as string) as long
	deflng i, seconds
	defstr res = ""

	for i = 1 to 24
		if hourmask[i] = mask[i]  then
			res.append hourmask[i]
		else
			res.append "0"
		end if
	next i

	seconds = 0
	for i = 1 to 24
		if res[i] = "1" then
			inc(seconds)
		end if
	next i
	seconds = seconds * 3600

	if mask[wrap(started.hours + 1] = "1" then
		seconds = seconds - started.minutes * 60 - started.seconds
	end if

	if mask[wrap(ended.hours + 1)] = "1" then
		seconds = seconds + ended.minutes * 60 + ended.seconds
	end if

	result = seconds
end function


function wrap(x as long) as long
	if x < 1 or x > 24 then
		result = 1
	else
		result = x
	end if
end function

jalski [18.05.2017 00:00:33]

#

... Ja vielä .NET toteutuskin kirjoiteltuna X#:llä. En .NET ohjelmointia ole harrastellut, joten varmaan löytyy tehokkaampia tapoja tehdä useimpia asioita.

EDIT: koodi poistettu, postitan uudelleen kunhan saan virheen korjattua...

Metabolix [18.05.2017 16:59:53]

#

Tuossa bittikikkailussa nyt ei ole mitään järkeä. Koodi rajoittuu tasatunteihin ja varmaankin käsittelee karkausvuodet ym. väärin.

Järkevä ratkaisu olisi irrottaa alku- ja loppuajankohdista päivämäärät, käydä silmukassa läpi päivät tuolta väliltä ja jokaisen päivän kohdalla tarkastaa kunkin kolmen työaikalajin määrä.

Siis tähän tapaan (kuvitteellisilla funktioilla, koska en tunne VB:n päivämääräfunktioita):

# käydään läpi eri päivät:
For p = alku.Date To loppu.Date
  # lasketaan jokainen työaikalaji tuolta päivältä:
  t_y = t_y + Max(0, DateDiff(Max(alku, p + " 00:00"), Min(loppu, p + " 06:00")))
  t_p = t_p + Max(0, DateDiff(Max(alku, p + " 06:00"), Min(loppu, p + " 18:00")))
  t_i = t_i + Max(0, DateDiff(Max(alku, p + " 18:00"), Min(loppu, p + " 24:00")))
Next p

Koodiakin tulee noin 80 riviä vähemmän kuin jalskin viritelmillä.

jalski [18.05.2017 22:05:25]

#

Metabolix kirjoitti:

Tuossa bittikikkailussa nyt ei ole mitään järkeä. Koodi rajoittuu tasatunteihin ja varmaankin käsittelee karkausvuodet ym. väärin.

Koodiakin tulee noin 80 riviä vähemmän kuin jalskin viritelmillä.

Ei rajoitu tasatunteihin, vaan laskee sekunnin tarkkuudella. Karkaussekunnit pitää käsitellä tietysti erikseen tarvittaessa, jos ei voi elää mahdollisen 1-2 sekunnin virheen kanssa vuorokauden kestossa sekunteina.

Mitä koodin pituuteen tulee, niin tuo muutama rivi PL/I-koodia mikä laskemiseen tarvitaan on varmasti pienempi kuin DateDiff() funktion sisältämä määrä koodia.

Kuinka itse kirjoittaisit funktion mikä laskee tuntilajin määrän vuorokaudessa käyttämättä valmista kirjastofunktiota ja saisitko sen lyhemmäksi kuin omat alla olevat neljä riviä PL/I-koodia?

result = hourmask & daymask;
seconds = (tally(result, '1'b)) * 3600;
if substr(daymask, wrap(substr(started, 12, 2)+1), 1) = '1'b then seconds -= substr(started, 15, 2) * 60 + substr(started, 18, 2);
if substr(daymask, wrap(substr(ended, 12, 2)+1), 1) = '1'b then seconds += substr(ended, 15, 2) * 60 + substr(ended,  18, 2);

groovyb [19.05.2017 04:58:28]

#

Mistä vaan saa one linerin jos ei vaan paina enteriä.
Mutta mitä tulee yleisesti esim .Netillä aika-alueiden käsittelyyn, on TimePeriod suosittu kirjasto, jolla nuo saa kaivettua näppärästi ilman mitään kikkailuja.

Mitään tarvetta bittimaskeille en kyllä näe vaikka kirjastoa ei käyttäisikään, miksi ei tekisi suoraan tarkistusta sille kuuluuko tunti mihinkin vuoroon, ja laskee siitä TimeSpanin suhteessa toteutuneeseen työaikaan? Lopuksi sitte ynnää eri vuoroihin saadut max tunnin mittaiset TimeSpanit yhteen vaikka millisekunnin tarkkuudella jos tykkää.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta