It seems i made a mistake in passing a value. Also, some of the c function calls seem to want to trash my values in the registers! Changes needed to run the code properly are commented with arrows.
NASM: Getting the day of the week a different date
Question
I have been tasked with writing a NASM program that gets the day of the week for the first day of the next month. As an example: If today is June 4, then the program should say something like:
July 1st is a Thursday.
I am using the mktime function as well as a few other time/date functions. Here is my code:
extern time
extern localtime
extern exit
extern printf
extern mktime
extern ctime
global main
section .data
sSun: db "Sunday", 0
sMon: db "Monday", 0
sTue: db "Tuesday", 0
sWed: db "Wednesday", 0
sThu: db "Thursday", 0
sFri: db "Friday", 0
sSat: db "Saturday", 0
format_1: db "%d", 10, 0
string: db "%s", 10, 0
section .bss
timestamp: resd 1
tmstruct: resd 1
section .text
main:
pusha
push dword 0 ; fetch the timestamp
call time
add esp, 4
mov [timestamp], eax
push timestamp
call localtime
add esp, 4
;change the localtime struct to indicate first day of next month.
;seconds, minutes, hours, day of month from 1.
mov [eax], dword 0
mov [eax + 4], dword 0
mov [eax + 8], dword 0
mov [eax + 12], dword 1
;get month # from 0, to ecx.
mov ecx, [eax + 16]
cmp ecx, 11
jne notDecember
;its december. Set date to January of next year.
mov [eax + 16], dword 0
mov ecx, [eax + 20]
inc ecx
mov [eax + 20], ecx
jmp convertDate
notDecember:
;its not december, just move up the month by 1.
mov ecx, [eax + 16]
inc ecx
mov [eax + 16], ecx
convertDate:
mov [tmstruct], eax
;make a timestamp
;push tmstruct <-- Wrong
push dword [tmstruct] ; <-- Right
call mktime
add esp, 4
;move timestamp
mov [timestamp], eax
;make a new tm struct
push timestamp
call localtime
add esp, 4
;now we have the correct date, check the day of the week
mov ecx, [eax + 24]
push ecx ;<--- preserve this value or c function calls will trash it!
;do a ctime call
;push dword eax <-- Wrong
push timestamp ; <-- Right
call ctime
add esp, 4
push dword eax
push string
call printf
add esp, 8
pop ecx ;<--- pop preserved value!
push dword ecx
call dayOfWeek
popa
call exit
dayOfWeek:
cmp [esp + 4], dword 0
je pSun
cmp [esp + 4], dword 1
je pMon
cmp [esp + 4], dword 2
je pTue
cmp [esp + 4], dword 3
je pWed
cmp [esp + 4], dword 4
je pThu
cmp [esp + 4], dword 5
je pFri
cmp [esp + 4], dword 6
je pSat
push dword esp
push format_1
call printf
add esp, 8
push format_1
jmp endDow
pSun:
push sSun
jmp endDow
pMon:
push sMon
jmp endDow
pTue:
push sTue
jmp endDow
pWed:
push sWed
jmp endDow
pThu:
push sThu
jmp endDow
pFri:
push sFri
jmp endDow
pSat:
push sSat
jmp endDow
endDow:
push string
call printf
add esp, 8
ret 4
Basically, i am told that "The mktime function ignores the specified contents of the structure members tm_wday and tm_yday..." (from localtime tm struct) "....and recomputes them from the other information in the broken-down time structure."
Seeing this as the case, my plan was to create a tm structure for the current time, and simply modify all its elements to point to the first second of the first day of the next month, then use mktime on that. However, you will see that the program outputs the "hijacked" struct as "Wed Dec 31 18:00:59 1969", but then i even print out the day of the week from THAT and i get sunday. What have i done to go so wrong here?
Solution 2
OTHER TIPS
Ok, I took the C Sample mktime and modified it to do what you want:
extern printf, time, mktime, exit, localtime, scanf,strftime
global main
;~ int tm_sec Seconds [0,60].
;~ int tm_min Minutes [0,59].
;~ int tm_hour Hour [0,23].
;~ int tm_mday Day of month [1,31].
;~ int tm_mon Month of year [0,11].
;~ int tm_year Years since 1900.
;~ int tm_wday Day of week [0,6] (Sunday =0).
;~ int tm_yday Day of year [0,365].
;~ int tm_isdst Daylight Savings flag.
%define tm_sec 0
%define tm_min 4
%define tm_hour 8
%define tm_mday 12
%define tm_mon 16
%define tm_year 20
%define tm_wday 24
%define tm_yday 28
%define tm_isdst 32
section .bss
timeinfo resd 1
rawtime resd 1
lpszBuffer resb 80
section .data
fmtdate db "%B %d %Y", 0
Sun db "Sunday", 0
Mon db "Monday", 0
Tue db "Tuesday", 0
Wed db "Wednsday", 0
Thu db "Thursday", 0
Fri db "Friday", 0
Sat db "Saturday", 0
WeekDay dd Sun, Mon, Tue, Wed, Thu, Fri, Sat
szThatDay db "%s is a %s", 10, 0
section .text
main:
;~ Get todays date
push rawtime
call time
add esp, 4 * 1
push rawtime
call localtime
add esp, 4 * 1
mov dword [timeinfo], eax
;~ Get current month and add one
mov edx, dword [eax + tm_mon]
inc edx
;~ move updated month back to structure
mov dword [eax + tm_mon], edx
;~ set day to the first
mov dword [eax + tm_mday], 1
push dword [timeinfo]
call mktime
add esp, 4 * 1
push dword [timeinfo]
push fmtdate
push 80
push lpszBuffer
call strftime
add esp, 4 * 4
mov eax, dword [timeinfo]
mov eax, dword [eax + tm_wday]
mov ecx, dword [WeekDay + 4 * eax]
push ecx
push lpszBuffer
push szThatDay
call printf
add esp, 4 * 3
call exit
Then to test, I displayed current date and ran the program which then showed the day of the week the 1st is of next month. I then changed the system clock and reran the test 2 more times. Test also worked under Windows.