module(..., lunit.testcase, package.seeall)

--print(LuaOrm.Date.__tostring)
--print(tostring(LuaOrm.Date))

print(LuaOrm.Date.isDstEnabled())

function testEpochFromString()
	local epoch = LuaOrm.Date("1970-01-01 00:00:00")
	assert_equal("1970-01-01 00:00:00.000", epoch:toString())
	
	local epoch = LuaOrm.Date("1970-01-02 00:00:00")
	assert_equal("1970-01-02 00:00:00.000", epoch:toString())
end

function testEpochFromTable()
	local epoch = LuaOrm.Date{ year=1970, month=1, day=1, hour=0, min=0, sec=0}
	assert_equal("1970-01-01 00:00:00.000", epoch:toString())
end

-- este test solo funciona si estoy en Montevideo con DST (-2)
--[[
function testLocalFromTable()
	local date = LuaOrm.Date{ year=2009, month=11, day=7, hour=20, min=16, sec=20, islocal = true}
	assert_equal("2009-11-07 22:16:20.000", date:toString())
	assert_equal("2009-11-07 22:16:20.000", tostring(date))
	assert_equal("2009-11-07 20:16:20.000", date:toLocalTimeString())
	
	local date = LuaOrm.Date{ year=1970, month=11, day=7, hour=20, min=16, sec=20, islocal = true}
	assert_equal("1970-11-07 22:16:20.000", date:toString())
	assert_equal("2009-11-07 22:16:20.000", tostring(date))
	assert_equal("2009-11-07 20:16:20.000", date:toLocalTimeString())
end
--]]

function testFromString()
	assert_equal("1970-01-01 14:01:22.000", LuaOrm.Date("2009-2-03 14:01:22"):toString())	-- no reconoce la fecha, asume el epoch
	assert_equal("1970-01-01 14:01:22.000", LuaOrm.Date("2009-2-3 14:01:22"):toString())	-- no reconoce la fecha, asume el epoch
	assert_equal("2009-03-02 14:01:22.000", LuaOrm.Date("03-02-2009 14:01:22"):toString())	-- reconoce como mes, dia, año
	assert_equal("2009-03-13 14:01:22.000", LuaOrm.Date("13-03-2009 14:01:22"):toString())	-- reconoce, y revolea los meses
	
	assert_equal("2009-03-12 14:01:22.000", LuaOrm.Date("2009-03-12 02:01:22 p.m."):toString())	-- reconoce, y revolea los meses
	assert_equal("2009-03-12 14:01:22.000", LuaOrm.Date("2009-03-12 02:01:22 pm"):toString())	-- reconoce, y revolea los meses
	assert_equal("2009-03-12 14:01:22.000", LuaOrm.Date("2009-03-12 02:01:22 PM"):toString())	-- reconoce, y revolea los meses
	
	assert_equal("2009-03-12 02:01:22.000", LuaOrm.Date("2009-03-12 02:01:22 a.m."):toString())	-- reconoce, y revolea los meses
	assert_equal("2009-03-12 02:01:22.000", LuaOrm.Date("2009-03-12 02:01:22 am"):toString())	-- reconoce, y revolea los meses
	assert_equal("2009-03-12 02:01:22.000", LuaOrm.Date("2009-03-12 02:01:22 AM"):toString())	-- reconoce, y revolea los meses
	
	-- y esto??
	--assert_equal("2009-03-12 12:01:22", LuaOrm.Date("2009-03-12 12:01:22 p.m."):toString())	-- reconoce, y revolea los meses
	
	assert_equal("2009-03-12 12:01:22.000", LuaOrm.Date("2009-03-12 12:01:22 a.m."):toString())	-- reconoce, y revolea los meses
	
	assert_equal("2009-03-12 13:01:22.000", tostring(LuaOrm.Date("2009-03-12 01:01:22 p.m.")))
	
	-- milliseconds
	assert_equal("2009-03-02 14:01:22.345", LuaOrm.Date("03-02-2009 14:01:22.345"):toString())
	assert_equal("2009-03-02 14:01:22.345", LuaOrm.Date("03-02-2009 02:01:22.345 PM"):toString())
	assert_equal("2009-03-02 14:01:22.345", LuaOrm.Date("03-02-2009 02:01:22.345 P.M."):toString())
	assert_equal("2009-03-02 02:01:22.345", LuaOrm.Date("03-02-2009 02:01:22.345 am"):toString())
	assert_equal("2009-03-02 02:01:22.345", LuaOrm.Date("03-02-2009 02:01:22.345 a.m."):toString())
	
	assert_equal("2009-03-02 14:01:22.345", LuaOrm.Date{year=2009, month=3, day=2, hour=14, min=1, sec=22, millisec=345}:toString())
	assert_equal("2009-03-02 14:01:22.345", LuaOrm.Date{year=2009, month=3, day=2, hour=14, min=1, sec=22, millisec=345}:toString())
	assert_equal("2009-03-02 14:01:22.345", LuaOrm.Date{year=2009, month=3, day=2, hour=14, min=1, sec=22, millisec=345}:toString())
	assert_equal("2009-03-02 02:01:22.345", LuaOrm.Date{year=2009, month=3, day=2, hour=2, min=1, sec=22, millisec=345}:toString())
	assert_equal("2009-03-02 02:01:22.345", LuaOrm.Date{year=2009, month=3, day=2, hour=2, min=1, sec=22, millisec=345}:toString())
end

function testMilliseconds()
	local d = LuaOrm.Date("03-02-2009 14:01:22.345")
	assert_equal("2009-03-02 14:01:22.345", d:toString())
	assert_equal(1236002482, d:time())
	assert_equal(1236002482345, d:timeInMilliseconds())
	assert_equal(345, d:milliseconds())
	
	d = LuaOrm.Date{year=2009, month=3, day=2, hour=14, min=1, sec=22, millisec=345}
	assert_equal("2009-03-02 14:01:22.345", d:toString())
	assert_equal(1236002482, d:time())
	assert_equal(1236002482345, d:timeInMilliseconds())
	assert_equal(345, d:milliseconds())
end

function testAddYear()
	local epoch = LuaOrm.Date("1970-01-01 00:00:00")
	local d = epoch:add(1)
	assert_not_equal(epoch, d)
	assert_equal("1971-01-01 00:00:00.000", d:toString())
	
	local newDate
	for i = 1970,2038 do
		newDate = epoch:add(i - 1970)
		local format = ("%i-01-01 00:00:00.000"):format(i)
		assert_equal(format, newDate:toString())
	end
end

function testAddMonth()
	local epoch = LuaOrm.Date("1970-01-01 00:00:00")
	local newDate
	for i = 1,11 do
		newDate = epoch:add(0, i)
		local format = ("1970-%02d-01 00:00:00.000"):format(i + 1)
		assert_equal(format, newDate:toString())
	end
	
	-- year lap
	newDate = epoch:add(0, 12)
	assert_equal("1971-01-01 00:00:00.000", newDate:toString())
	newDate = epoch:add(0, 13)
	assert_equal("1971-02-01 00:00:00.000", newDate:toString())
	newDate = epoch:add(0, 24)
	assert_equal("1972-01-01 00:00:00.000", newDate:toString())
	newDate = epoch:add(0, 12 * 46)
	assert_equal("2016-01-01 00:00:00.000", newDate:toString())
	-- este test no anda en linux
	--newDate = epoch:add(0, 12 * 68)
	--assert_equal("2038-01-01 00:00:00.000", newDate:toString())
end

function testAddDays()
	local epoch = LuaOrm.Date("1970-01-01 00:00:00")
	local newDate
	for i = 1,30 do
		newDate = epoch:add(0, 0, i)
		local format = ("1970-01-%02d 00:00:00.000"):format(i + 1)
		assert_equal(format, newDate:toString())
	end
	
	newDate = epoch:add(0, 0, 31)
	assert_equal("1970-02-01 00:00:00.000", newDate:toString())
	
	-- On 1990-10-10 there were no DST on Montevideo, but 5 days later there was
	newDate = LuaOrm.Date("1990-10-10 00:00:00"):add(0, 0, 5)
	assert_equal("1990-10-15 00:00:00.000", newDate:toString())
	
	newDate = epoch:add(0, 0, 365)
	assert_equal("1971-01-01 00:00:00.000", newDate:toString())
	
	newDate = epoch:add(0, 0, 365 * 2)
	assert_equal("1972-01-01 00:00:00.000", newDate:toString())
	
	-- takes leap years into account
	newDate = epoch:add(0, 0, 365 * 60)
	assert_equal("2029-12-17 00:00:00.000", newDate:toString())
end

function testSubstractDays()
	local start = LuaOrm.Date("2030-01-01 00:00:00")
	local newDate
	
	newDate = start:add(0, 0, -31)
	assert_equal("2029-12-01 00:00:00.000", newDate:toString())
	
	newDate = start:add(0, 0, -365)
	assert_equal("2029-01-01 00:00:00.000", newDate:toString())
	
	newDate = start:add(0, 0, -365 * 2)
	assert_equal("2028-01-02 00:00:00.000", newDate:toString())
	
	-- takes leap years into account
	newDate = start:add(0, 0, -365 * 60)
	assert_equal("1970-01-16 00:00:00.000", newDate:toString())
	
	-- On 1990-10-15 there were no DST on Montevideo, but 5 days before there was
	newDate = LuaOrm.Date("1990-10-15 00:00:00"):add(0, 0, -5)
	assert_equal("1990-10-10 00:00:00.000", newDate:toString())
end

function testDifferentTimezones()
	local date = LuaOrm.Date("1990-01-01 00:00:00")
	assert_equal("1990-01-01 03:00:00.000", date:toDifferentTimezoneString({ offset = 3 }))
	assert_equal("1990-01-01 04:00:00.000", date:toDifferentTimezoneString({ offset = 3, dst = true }))
	assert_equal("1989-12-31 21:00:00.000", date:toDifferentTimezoneString({ offset = -3 }))
	assert_equal("1989-12-31 22:00:00.000", date:toDifferentTimezoneString({ offset = -3, dst = true }))
	assert_equal("1990-01-01 04:30:00.000", date:toDifferentTimezoneString({ offset = 3, minutes=30, dst = true }))
	assert_equal("1989-12-31 20:30:00.000", date:toDifferentTimezoneString({ offset = -3, minutes=30 }))
	assert_equal("1989-12-31 21:30:00.000", date:toDifferentTimezoneString({ offset = -3, minutes=30, dst = true }))
	
	assert_equal(631141200, date:toDifferentTimezone({ offset = -3 }):time())
	assert_equal(631144800, date:toDifferentTimezone({ offset = -3, dst = true }):time())
end

function testTime()
	local date = LuaOrm.Date("2009-11-07 19:09:00")
	assert_number(date:time())
	assert_equal(1257620940, date:time())
	assert_equal(date:toString(), os.date("!%Y-%m-%d %H:%M:%S.000", date:time()))
	
	assert_equal("2009-11-07 16:09:00", os.date("!%Y-%m-%d %H:%M:%S", date:toDifferentTimezone({ offset = -3 }):time()))
end

function testDate()
	local fecha = LuaOrm.Date("2009-11-07 19:09:00")
	
	assert_table(fecha:date())
	assert_equal(2009, fecha:date().year)
	assert_equal(11, fecha:date().month)
	assert_equal(7, fecha:date().day)
	assert_equal(19, fecha:date().hour)
	assert_equal(9, fecha:date().min)
	assert_equal(0, fecha:date().sec)
	assert_false(false, fecha:date().isdst)	-- always false in UTC
end

-- este test solo funciona si estoy en Montevideo con DST (-2)
function testDateLocal()
	local fecha = LuaOrm.Date("2009-11-07 19:09:00")
	
	assert_table(fecha:dateLocal())
	assert_equal(2009, fecha:dateLocal().year)
	assert_equal(11, fecha:dateLocal().month)
	assert_equal(7, fecha:dateLocal().day)
	assert_equal(17, fecha:dateLocal().hour)
	assert_equal(9, fecha:dateLocal().min)
	assert_equal(0, fecha:dateLocal().sec)
	assert_true(fecha:dateLocal().isdst)	-- always false in UTC
end

function testCompare()
	local fecha1 = LuaOrm.Date("2009-11-07 19:09:00")
	local fecha2 = LuaOrm.Date("2010-11-07 19:09:00")
	
	assert_true(fecha1:compare(fecha2))	-- fecha1 < fecha2 ?
	assert_false(fecha2:compare(fecha1))-- fecha2 > fecha1 ?
end

function testEquals()
	local fecha1 = LuaOrm.Date("2009-11-07 19:09:00")
	local fecha2 = LuaOrm.Date("2010-11-07 19:09:00")
	local fecha3 = LuaOrm.Date("2009-11-07 19:09:00")
	
	assert_false(fecha1:equals(fecha2))	-- fecha1 == fecha2 ?
	assert_true(fecha1:equals(fecha1))	-- fecha1 == fecha1 ?
	
	assert_true(fecha1:equals(fecha3))	-- fecha1 == fecha3 ?
	assert_false(fecha1:equals({}))	-- fecha1 == {} ?
	assert_false(fecha1:equals(22))	-- fecha1 == 22 ?
end

function testFields()
	local date = LuaOrm.Date("2009-11-07 19:09:32")
	assert_equal(2009, date:year())
	assert_equal(11, date:month())
	assert_equal(7, date:day())
	assert_equal(44, date:week())
	assert_equal(5, date:weeksInMonth())
	assert_equal(4, LuaOrm.Date("2009-02-07 19:09:32"):weeksInMonth())
	assert_equal(311, date:dayOfYear())
	assert_equal(7, date:dayOfWeek())
	assert_equal(1, LuaOrm.Date("2009-11-08 19:09:32"):dayOfWeek())	-- el domingo es 1
	
	assert_equal(19, date:hour())
	assert_equal(9, date:minute())
	assert_equal(32, date:second())
	
	assert_true(LuaOrm.Date("2009-11-07"):equals(date:dayDate()))
	assert_true(LuaOrm.Date("2009-11-01"):equals(date:weekDate()))	-- fecha en que comenzó esa semana
	assert_true(LuaOrm.Date("2009-11-07 23:59:59"):equals(date:weekEndDate()))-- fecha en que termina esa semana
	assert_true(LuaOrm.Date("2009-11-01"):equals(date:monthDate()))	-- fecha al primero de ese més
	assert_true(LuaOrm.Date("2009-01-01"):equals(date:yearDate()))	-- fecha al primero de ese año
	
	assert_true(LuaOrm.Date("2009-11-07 23:59:59"):equals(date:dayEndDate()))-- fecha al final del día
	assert_true(LuaOrm.Date("2009-11-30 23:59:59"):equals(date:monthEndDate()))-- fecha al final del mes
	assert_true(LuaOrm.Date("2009-12-31 23:59:59"):equals(date:yearEndDate()))-- fecha al final del año
end

function testIntervals()
	local date = LuaOrm.Date("2009-02-03 14:01:22")
	local dateEnd = LuaOrm.Date("2009-11-07 19:09:32")
	
	--Y = Year, M = Month, W = Week, D = Day, h = Hour, m = Minute, s = Second
	assert_equal(23951290, date:interval(dateEnd))	-- seconds by default
	
	assert_equal(0, date:interval(dateEnd, "Y"))	-- years
	assert_equal(8, date:interval(dateEnd, "M"))	-- months
	assert_equal(39, date:interval(dateEnd, "W"))	-- weeks
	assert_equal(277, date:interval(dateEnd, "D"))	-- days
	assert_equal(6653, date:interval(dateEnd, "h"))	-- hours
	assert_equal(399188, date:interval(dateEnd, "m"))	-- minutes
	assert_equal(23951290, date:interval(dateEnd, "s"))	-- seconds
end

function testFromLocalTime()
	-- construye fechas UTC a partir de horas locales. el timezone se pasa en una tabla
	local tz = { offset = -3, minutes = 30, dst = true }
	local date = LuaOrm.Date()
	assert_equal(LuaOrm.Date("2009-12-12 22:00:00"):toString(), date:newFromDifferentTimezone("2009-12-12 19:30:00", tz):toString())
	
	local tz = { offset = -3, minutes = 0, dst = false }
	local date = LuaOrm.Date()
	assert_equal(LuaOrm.Date("2009-12-12 22:30:00"):toString(), date:newFromDifferentTimezone("2009-12-12 19:30:00", tz):toString())
end

function testJulianDay()
	local date = LuaOrm.Date("2009-02-03 14:01:22")
	assert_equal(2454866, date:julianDay())
	
	assert_equal(LuaOrm.Date("2009-02-03"):toString(), LuaOrm.Date():dateWithJulianDay(2454866):toString())
end

-- Constructs dates using number of seconds since the epoch
function testFromNumber()
	local date = LuaOrm.Date(0)
	assert_equal("1970-01-01 00:00:00.000", date:toString())
	
	date = LuaOrm.Date(979021291)
	assert_equal("2001-01-09 06:21:31.000", date:toString())
	
	date = LuaOrm.Date("2001-01-09 06:21:31.000")
	assert_equal(date:time(), 979021291)
end
