-module(ecrontab_next_time). -include("ecrontab_parse.hrl"). -export([ next_timestamp/1, next_timestamp/2, next_timestamp/3, next_seconds/1, next_seconds/2, next_seconds/3, next_datetime/1, next_datetime/2, next_datetime/3, next_time/1, next_time/2, next_time/3 ]). %% ==================================================================== %% API %% ==================================================================== next_timestamp(Spec) -> next_timestamp(Spec, erlang:localtime()). next_timestamp(Spec, NowDatetime) -> next_timestamp(Spec, NowDatetime, []). next_timestamp(Spec, NowDatetime, _Options) -> case next_time_do(Spec, NowDatetime) of {ok, Datetime} -> {ok, ecrontab_time_util:datetime_to_timestamp(Datetime)}; Err -> Err end. next_seconds(Spec) -> next_seconds(Spec, erlang:localtime()). next_seconds(Spec, NowDatetime) -> next_seconds(Spec, NowDatetime, []). next_seconds(Spec, NowDatetime, _Options) -> case next_time_do(Spec, NowDatetime) of {ok, Datetime} -> {ok, calendar:datetime_to_gregorian_seconds(Datetime)}; Err -> Err end. next_datetime(Spec) -> next_datetime(Spec, erlang:localtime()). next_datetime(Spec, NowDatetime) -> next_datetime(Spec, NowDatetime, []). next_datetime(Spec, NowDatetime, _Options) -> next_time_do(Spec, NowDatetime). %% ==================================================================== %% next_time %% ==================================================================== next_time(Spec) -> next_time(Spec, erlang:localtime(), []). -spec next_time(Spec :: spec(), NowDatetime :: calendar:datetime()) -> {ok, NextTime :: non_neg_integer() | calendar:datetime() | non_neg_integer()} | {false, time_over}. next_time(Spec, NowDatetime) -> next_time(Spec, NowDatetime, []). next_time(Spec, NowDatetime, Options) -> case next_time_do(Spec, NowDatetime) of {ok, NextDatetime} = Result -> case proplists:get_value(return , Options) of datetime -> Result; timestamp -> {ok, ecrontab_time_util:datetime_to_timestamp(NextDatetime)}; seconds -> {ok, calendar:datetime_to_gregorian_seconds(NextDatetime)}; _ -> Result end; Err -> Err end. next_time_do(#spec{type = ?SPEC_TYPE_INTERVAL_YEAR, year = #spec_field{type = ?SPEC_FIELD_TYPE_INTERVAL,value = Interval}} = Spec, NowDatetime) -> {{LastYear,_,_},_} = NowDatetime, NextYear = LastYear+Interval, SpecField = #spec_field{type = ?SPEC_FIELD_TYPE_NUM,value = NextYear}, NewSpec = ecrontab_parse:get_spec_type(Spec#spec{year = SpecField}), next_time_do(NewSpec, NowDatetime); next_time_do(#spec{type=?SPEC_TYPE_EVERY_SECOND}, NowDatetime) -> {ok, ecrontab_time_util:next_second(NowDatetime)}; next_time_do(#spec{type=?SPEC_TYPE_SECONDS,value=Seconds}, NowDatetime) -> Datetime = calendar:gregorian_seconds_to_datetime(Seconds), if Datetime > NowDatetime -> {ok, Datetime}; true -> {false, time_over} end; next_time_do(#spec{type=?SPEC_TYPE_ONLY_ONE,value=N}=Spec, NowDatetime) -> next_time_only_one(N, Spec, NowDatetime); next_time_do(Spec, NowDatetime) -> #spec{year = Year, month = Month, day = Day, week = Week, hour = Hour, minute = Minute, second = Second} = Spec, next_time_year(Year, Month, Day, Week, Hour, Minute, Second, NowDatetime). %% ==================================================================== %% next_time_year %% ==================================================================== next_time_year(#spec_field{type = ?SPEC_FIELD_TYPE_ANY}, Month, Day, Week, Hour, Minute, Second, NowDatetime) -> NowYear = ecrontab_time_util:get_datetime_year(NowDatetime), next_time_year_any(NowYear, Month, Day, Week, Hour, Minute, Second, NowDatetime); next_time_year(#spec_field{type = ?SPEC_FIELD_TYPE_NUM, value = Year}, Month, Day, Week, Hour, Minute, Second, NowDatetime) -> NowYear = ecrontab_time_util:get_datetime_year(NowDatetime), if Year < NowYear -> {false, time_over}; true -> case next_time_month(Year, Month, Day, Week, Hour, Minute, Second, NowDatetime) of false -> {false, time_over}; Result -> Result end end; next_time_year(#spec_field{type = ?SPEC_FIELD_TYPE_LIST, value = List}, Month, Day, Week, Hour, Minute, Second, NowDatetime) -> NowYear = ecrontab_time_util:get_datetime_year(NowDatetime), case ordsets:is_element(NowYear, List) of true -> case next_time_month(NowYear, Month, Day, Week, Hour, Minute, Second, NowDatetime) of false -> next_time_year_list(NowYear, List, Month, Day, Week, Hour, Minute, Second, NowDatetime); Result -> Result end; false -> next_time_year_list(NowYear, List, Month, Day, Week, Hour, Minute, Second, NowDatetime) end. next_time_year_any(NowYear, Month, Day, Week, Hour, Minute, Second, NowDatetime) -> case next_time_month(NowYear, Month, Day, Week, Hour, Minute, Second, NowDatetime) of false -> next_time_year_any(NowYear+1, Month, Day, Week, Hour, Minute, Second, NowDatetime); Result -> Result end. next_time_year_list(NowYear, List, Month, Day, Week, Hour, Minute, Second, NowDatetime) -> case find_next_in_list(NowYear, List) of false -> {false, time_over}; NextYear -> case next_time_month(NextYear, Month, Day, Week, Hour, Minute, Second, NowDatetime) of false -> next_time_year_list(NextYear, List, Month, Day, Week, Hour, Minute, Second, NowDatetime); Result -> Result end end. %% ==================================================================== %% next_time_month %% ==================================================================== next_time_month(Year, #spec_field{type = ?SPEC_FIELD_TYPE_ANY}, Day, Week, Hour, Minute, Second, NowDatetime) -> case NowDatetime of {{Year,NowMonth,_},_} -> next_time_month_any(Year, NowMonth, Day, Week, Hour, Minute, Second, NowDatetime); _ -> next_time_month_any(Year, 1, Day, Week, Hour, Minute, Second, NowDatetime) end; next_time_month(Year, #spec_field{type = ?SPEC_FIELD_TYPE_NUM,value = Month}, Day, Week, Hour, Minute, Second, NowDatetime) -> case NowDatetime of {{Year,NowMonth,_},_} when NowMonth < Month -> false; _ -> next_time_day_or_week(Year, Month, Day, Week, Hour, Minute, Second, NowDatetime) end; next_time_month(Year, #spec_field{type = ?SPEC_FIELD_TYPE_LIST,value = List}, Day, Week, Hour, Minute, Second, NowDatetime) -> case NowDatetime of {{Year,NowMonth,_},_} -> case ordsets:is_element(NowMonth, List) of true -> case next_time_day_or_week(Year, NowMonth, Day, Week, Hour, Minute, Second, NowDatetime) of false -> next_time_month_list(Year, NowMonth, List, Day, Week, Hour, Minute, Second, NowDatetime); Result -> Result end; false -> next_time_month_list(Year, NowMonth, List, Day, Week, Hour, Minute, Second, NowDatetime) end; _ -> NextMonth = hd(List), case next_time_day_or_week(Year, NextMonth, Day, Week, Hour, Minute, Second, NowDatetime) of false -> next_time_month_list(Year, NextMonth, List, Day, Week, Hour, Minute, Second, NowDatetime); Result -> Result end end. next_time_month_any(Year, NowMonth, Day, Week, Hour, Minute, Second, NowDatetime) -> case next_time_day_or_week(Year, NowMonth, Day, Week, Hour, Minute, Second, NowDatetime) of false -> case NowMonth of 12 -> false; _ -> next_time_month_any(Year, NowMonth+1, Day, Week, Hour, Minute, Second, NowDatetime) end; Result -> Result end. next_time_month_list(Year, NowMonth, List, Day, Week, Hour, Minute, Second, NowDatetime) -> case find_next_in_list(NowMonth, List) of false -> false; NextMonth -> case next_time_day_or_week(Year, NextMonth, Day, Week, Hour, Minute, Second, NowDatetime) of false -> next_time_month_list(Year, NextMonth, List, Day, Week, Hour, Minute, Second, NowDatetime); Result -> Result end end. %% ==================================================================== %% next_time_day_or_week %% ==================================================================== next_time_day_or_week(Year, Month, Day, Week, Hour, Minute, Second, NowDatetime) -> case {Day#spec_field.type, Week#spec_field.type} of {_, ?SPEC_FIELD_TYPE_ANY} -> next_time_day(Year, Month, Day, Hour, Minute, Second, NowDatetime); {?SPEC_FIELD_TYPE_ANY, ?SPEC_FIELD_TYPE_ANY} -> next_time_day(Year, Month, Day, Hour, Minute, Second, NowDatetime); {?SPEC_FIELD_TYPE_ANY, _} -> next_time_week(Year, Month, Week, Hour, Minute, Second, NowDatetime); _ -> case {next_time_day(Year, Month, Day, Hour, Minute, Second, NowDatetime), next_time_week(Year, Month, Week, Hour, Minute, Second, NowDatetime)} of {false, false} -> false; {false, Result} -> Result; {Result, false} -> Result; {{ok, Seconds1}, {ok, Seconds2}} when Seconds1 < Seconds2 -> {ok, Seconds1}; {_, Result} -> Result end end. %% ==================================================================== %% next_time_day %% ==================================================================== next_time_day(Year, Month, #spec_field{type = ?SPEC_FIELD_TYPE_ANY}, Hour, Minute, Second, NowDatetime) -> case NowDatetime of {{Year,Month,NowDay},_} -> next_time_day_any(Year, Month, NowDay, Hour, Minute, Second, NowDatetime); _ -> next_time_day_any(Year, Month, 1, Hour, Minute, Second, NowDatetime) end; next_time_day(Year, Month, #spec_field{type = ?SPEC_FIELD_TYPE_NUM,value = Day}, Hour, Minute, Second, NowDatetime) -> case NowDatetime of {{Year,Month,NowDay},_} when NowDay > Day -> false; _ -> LastDay = calendar:last_day_of_the_month(Year, Month), if Day > LastDay -> false; true -> Date = {Year, Month, Day}, next_time_hour(Date, Hour, Minute, Second, NowDatetime) end end; next_time_day(Year, Month, #spec_field{type = ?SPEC_FIELD_TYPE_LIST,value = List}, Hour, Minute, Second, NowDatetime) -> case NowDatetime of {{Year,Month,NowDay}=NowDate,_} -> case ordsets:is_element(NowDay, List) of true -> case next_time_hour(NowDate, Hour, Minute, Second, NowDatetime) of false -> LastDay = calendar:last_day_of_the_month(Year, Month), next_time_day_list(Year, Month, NowDay, LastDay, List, Hour, Minute, Second, NowDatetime); Result -> Result end; false -> LastDay = calendar:last_day_of_the_month(Year, Month), next_time_day_list(Year, Month, NowDay, LastDay, List, Hour, Minute, Second, NowDatetime) end; _ -> LastDay = calendar:last_day_of_the_month(Year, Month), NextDay = hd(List), if NextDay > LastDay -> false; true -> case next_time_hour({Year, Month, NextDay}, Hour, Minute, Second, NowDatetime) of false -> next_time_day_list(Year, Month, NextDay, LastDay, List, Hour, Minute, Second, NowDatetime); Result -> Result end end end. next_time_day_any(Year, Month, NowDay, Hour, Minute, Second, NowDatetime) -> case next_time_hour({Year, Month, NowDay}, Hour, Minute, Second, NowDatetime) of false -> LastDay = calendar:last_day_of_the_month(Year, Month), case NowDay of LastDay -> false; _ -> next_time_day_any_do(Year, Month, NowDay+1, LastDay, Hour, Minute, Second, NowDatetime) end; Result -> Result end. next_time_day_any_do(Year, Month, NowDay, LastDay, Hour, Minute, Second, NowDatetime) -> case next_time_hour({Year, Month, NowDay}, Hour, Minute, Second, NowDatetime) of false -> case NowDay of LastDay -> false; _ -> next_time_day_any_do(Year, Month, NowDay+1, LastDay, Hour, Minute, Second, NowDatetime) end; Result -> Result end. next_time_day_list(Year, Month, NowDay, LastDay, List, Hour, Minute, Second, NowDatetime) -> case find_next_in_list(NowDay, List) of false -> false; NextDay when NextDay > LastDay -> false; NextDay -> case next_time_hour({Year, Month, NextDay}, Hour, Minute, Second, NowDatetime) of false -> next_time_day_list(Year, Month, NextDay, LastDay, List, Hour, Minute, Second, NowDatetime); Result -> Result end end. %% ==================================================================== %% next_time_week %% ==================================================================== next_time_week(Year, Month, #spec_field{type = ?SPEC_FIELD_TYPE_NUM,value = Week}, Hour, Minute, Second, NowDatetime) -> case NowDatetime of {{Year,Month,NowDay}=NowDate,_} -> case calendar:day_of_the_week(Year, Month, NowDay) of Week -> case next_time_hour(NowDate, Hour, Minute, Second, NowDatetime) of false -> next_time_week_num(Year, Month, NowDay, Week, Hour, Minute, Second, NowDatetime); Result -> Result end; _ -> next_time_week_num(Year, Month, NowDay, Week, Hour, Minute, Second, NowDatetime) end; _ -> case calendar:day_of_the_week(Year, Month, 1) of Week -> case next_time_hour({Year, Month, 1}, Hour, Minute, Second, NowDatetime) of false -> next_time_week_num(Year, Month, 1, Week, Hour, Minute, Second, NowDatetime); Result -> Result end; _ -> next_time_week_num(Year, Month, 1, Week, Hour, Minute, Second, NowDatetime) end end; next_time_week(Year, Month, #spec_field{type = ?SPEC_FIELD_TYPE_LIST,value = List}, Hour, Minute, Second, NowDatetime) -> LastDay = calendar:last_day_of_the_month(Year, Month), DateWeekList = case NowDatetime of {{Year,Month,NowDay},_} -> Week = calendar:day_of_the_week(Year, Month, NowDay), get_date_week_list(Year, Month, NowDay, LastDay, Week); _ -> Week = calendar:day_of_the_week(Year, Month, 1), get_date_week_list(Year, Month, 1, LastDay, Week) end, next_time_week_list(DateWeekList, List, Hour, Minute, Second, NowDatetime). next_time_week_num(Year, Month, Day, Week, Hour, Minute, Second, NowDatetime) -> case get_next_week_date(Week, Year, Month, Day) of false -> false; Date -> case next_time_hour(Date, Hour, Minute, Second, NowDatetime) of false -> next_time_week_num(Year, Month, Day, Week, Hour, Minute, Second, NowDatetime); Result -> Result end end. get_date_week_list(Year, Month, LastDay, LastDay, Week) -> [{{Year, Month, LastDay},Week}]; get_date_week_list(Year, Month, Day, LastDay, 7) -> [{{Year, Month, Day},7}|get_date_week_list(Year, Month, Day+1, LastDay, 1)]; get_date_week_list(Year, Month, Day, LastDay, Week) -> [{{Year, Month, Day},Week}|get_date_week_list(Year, Month, Day+1, LastDay, Week+1)]. next_time_week_list([], _, _, _, _, _) -> false; next_time_week_list([{Date,Week}| DateWeekList], List, Hour, Minute, Second, NowDatetime) -> case ordsets:is_element(Week, List) of true -> case next_time_hour(Date, Hour, Minute, Second, NowDatetime) of false -> next_time_week_list(DateWeekList, List, Hour, Minute, Second, NowDatetime); Result -> Result end; false -> next_time_week_list(DateWeekList, List, Hour, Minute, Second, NowDatetime) end. get_next_week_date(Week, Year, Month, Day) -> NowWeek = calendar:day_of_the_week(Year, Month, Day), DiffDays = if NowWeek == Week -> 7; NowWeek > Week -> 7 - (NowWeek - Week); true -> Week - NowWeek end, NowDays = calendar:date_to_gregorian_days(Year, Month, Day), NewDays = NowDays + DiffDays, case calendar:gregorian_days_to_date(NewDays) of {Year,Month,_} = NewDate -> NewDate; _ -> false end. %% ==================================================================== %% next_time_hour %% ==================================================================== next_time_hour(Date, #spec_field{type = ?SPEC_FIELD_TYPE_ANY}, Minute, Second, NowDatetime) -> case NowDatetime of {Date, {NowHour,_,_}} -> next_time_hour_any(Date, NowHour, Minute, Second, NowDatetime); _ -> next_time_hour_any(Date, 0, Minute, Second, NowDatetime) end; next_time_hour(Date, #spec_field{type = ?SPEC_FIELD_TYPE_NUM,value = Hour}, Minute, Second, NowDatetime) -> case NowDatetime of {Date, {NowHour,_,_}} when NowHour > Hour -> false; _ -> next_time_minute(Date, Hour, Minute, Second, NowDatetime) end; next_time_hour(Date, #spec_field{type = ?SPEC_FIELD_TYPE_LIST,value = List}, Minute, Second, NowDatetime) -> case NowDatetime of {Date,{NowHour,_,_}} -> case ordsets:is_element(NowHour, List) of true -> case next_time_minute(Date, NowHour, Minute, Second, NowDatetime) of false -> next_time_hour_list(Date, NowHour, List, Minute, Second, NowDatetime); Result -> Result end; false -> next_time_hour_list(Date, NowHour, List, Minute, Second, NowDatetime) end; _ -> NextHour = hd(List), case next_time_minute(Date, NextHour, Minute, Second, NowDatetime) of false -> next_time_hour_list(Date, NextHour, List, Minute, Second, NowDatetime); Result -> Result end end. next_time_hour_any(Date, NowHour, Minute, Second, NowDatetime) -> case next_time_minute(Date, NowHour, Minute, Second, NowDatetime) of false -> case NowHour of 23 -> false; _ -> next_time_hour_any(Date, NowHour+1, Minute, Second, NowDatetime) end; Result -> Result end. next_time_hour_list(Date, NowHour, List, Minute, Second, NowDatetime) -> case find_next_in_list(NowHour, List) of false -> false; NextHour -> case next_time_minute(Date, NextHour, Minute, Second, NowDatetime) of false -> next_time_hour_list(Date, NowHour, List, Minute, Second, NowDatetime); Result -> Result end end. %% ==================================================================== %% next_time_minute %% ==================================================================== next_time_minute(Date, Hour, #spec_field{type = ?SPEC_FIELD_TYPE_ANY}, Second, NowDatetime) -> case NowDatetime of {Date,{Hour,NowMinute,_}} -> next_time_minute_any(Date, Hour, NowMinute, Second, NowDatetime); _ -> next_time_minute_any(Date, Hour, 0, Second, NowDatetime) end; next_time_minute(Date, Hour, #spec_field{type = ?SPEC_FIELD_TYPE_NUM,value = Minute}, Second, NowDatetime) -> case NowDatetime of {Date,{Hour,NowMinute,_}} when NowMinute > Minute -> false; _ -> next_time_second(Date, Hour, Minute, Second, NowDatetime) end; next_time_minute(Date, Hour, #spec_field{type = ?SPEC_FIELD_TYPE_LIST,value = List}, Second, NowDatetime) -> case NowDatetime of {Date,{Hour,NowMinute,_}} -> case ordsets:is_element(NowMinute,List) of true -> case next_time_second(Date, Hour, NowMinute, Second, NowDatetime) of false -> next_time_minute_list(Date, Hour, NowMinute, List, Second, NowDatetime); Result -> Result end; false -> next_time_minute_list(Date, Hour, NowMinute, List, Second, NowDatetime) end; _ -> NextMinute = hd(List), case next_time_second(Date, Hour, NextMinute, Second, NowDatetime) of false -> next_time_minute_list(Date, Hour, NextMinute, List, Second, NowDatetime); Result -> Result end end. next_time_minute_any(Date, Hour, NowMinute, Second, NowDatetime) -> case next_time_second(Date, Hour, NowMinute, Second, NowDatetime) of false -> case NowMinute of 59 -> false; _ -> next_time_minute_any(Date, Hour, NowMinute+1, Second, NowDatetime) end; Result -> Result end. next_time_minute_list(Date, Hour, NowMinute, List, Second, NowDatetime) -> case find_next_in_list(NowMinute,List) of false -> false; NextMinute -> case next_time_second(Date, Hour, NextMinute, Second, NowDatetime) of false -> next_time_minute_list(Date, Hour, NextMinute, List, Second, NowDatetime); Result -> Result end end. %% ==================================================================== %% next_time_second %% ==================================================================== next_time_second(Date, Hour, Minute, #spec_field{type = ?SPEC_FIELD_TYPE_ANY}, NowDatetime) -> case NowDatetime of {Date,{Hour,Minute,NowSecond}} -> next_time_second_any(Date, Hour, Minute, NowSecond, NowDatetime); _ -> next_time_second_any(Date, Hour, Minute, 0, NowDatetime) end; next_time_second(Date, Hour, Minute, #spec_field{type = ?SPEC_FIELD_TYPE_NUM,value = Second}, NowDatetime) -> case NowDatetime of {Date,{Hour,Minute,NowSecond}} -> if NowSecond >= Second -> false; true -> {ok, {Date, {Hour, Minute, Second}}} end; _ -> {ok, {Date, {Hour, Minute, Second}}} end; next_time_second(Date, Hour, Minute, #spec_field{type = ?SPEC_FIELD_TYPE_LIST,value = List}, NowDatetime) -> case NowDatetime of {Date,{Hour,Minute,NowSecond}} -> next_time_second_list(Date, Hour, Minute, NowSecond, List, NowDatetime); _ -> NextSecond = hd(List), Datetime = {Date, {Hour,Minute,NextSecond}}, if Datetime > NowDatetime -> {ok, Datetime}; true -> next_time_second_list(Date, Hour, Minute, NextSecond, List, NowDatetime) end end. next_time_second_any(Date, Hour, Minute, NowSecond, NowDatetime) -> Datetime = {Date, {Hour,Minute,NowSecond}}, if Datetime > NowDatetime -> {ok, Datetime}; true -> case NowSecond of 59 -> false; _ -> next_time_second_any(Date, Hour, Minute, NowSecond+1, NowDatetime) end end. next_time_second_list(Date, Hour, Minute, NowSecond, List, NowDatetime) -> case find_next_in_list(NowSecond,List) of false -> false; NextSecond -> Datetime = {Date, {Hour,Minute,NextSecond}}, if Datetime > NowDatetime -> {ok, Datetime}; true -> next_time_second_list(Date, Hour, Minute, NextSecond, List, NowDatetime) end end. %% ==================================================================== %% next_time_only_one start %% ==================================================================== next_time_only_one(#spec.year,Spec,NowDatetime) -> SpecField = Spec#spec.year, NowYear = ecrontab_time_util:get_datetime_year(NowDatetime), case is_passed_spec_field(NowYear, SpecField) of true -> NewDatetime = ecrontab_time_util:next_second(NowDatetime), case ecrontab_time_util:get_datetime_year(NewDatetime) of NowYear -> {ok, NewDatetime}; _ -> next_time_only_one_year(SpecField,NowDatetime) end; false -> next_time_only_one_year(SpecField,NowDatetime) end; next_time_only_one(#spec.month,Spec,NowDatetime) -> SpecField = Spec#spec.month, NowMonth = ecrontab_time_util:get_datetime_month(NowDatetime), case is_passed_spec_field(NowMonth, SpecField) of true -> NewDatetime = ecrontab_time_util:next_second(NowDatetime), case ecrontab_time_util:get_datetime_month(NewDatetime) of NowMonth -> {ok, NewDatetime}; _ -> next_time_only_one_month(SpecField,NowDatetime) end; false -> next_time_only_one_month(SpecField,NowDatetime) end; next_time_only_one(#spec.day,Spec,NowDatetime) -> SpecField = Spec#spec.day, NowDay = ecrontab_time_util:get_datetime_day(NowDatetime), case is_passed_spec_field(NowDay, SpecField) of true -> NewDatetime = ecrontab_time_util:next_second(NowDatetime), case ecrontab_time_util:get_datetime_day(NewDatetime) of NowDay -> {ok, NewDatetime}; _ -> next_time_only_one_day(SpecField,NowDatetime) end; false -> next_time_only_one_day(SpecField,NowDatetime) end; next_time_only_one(#spec.week,Spec,NowDatetime) -> NowWeek = calendar:day_of_the_week(element(1,NowDatetime)), SpecField = Spec#spec.week, case is_passed_spec_field(NowWeek, SpecField) of true -> NewDatetime = ecrontab_time_util:next_second(NowDatetime), case ecrontab_time_util:get_datetime_week(NewDatetime) of NowWeek -> {ok, NewDatetime}; _ -> next_time_only_one_week(SpecField,NowWeek,NowDatetime) end; false -> next_time_only_one_week(SpecField,NowWeek,NowDatetime) end; next_time_only_one(#spec.hour,Spec,NowDatetime) -> SpecField = Spec#spec.hour, NowHour = ecrontab_time_util:get_datetime_hour(NowDatetime), case is_passed_spec_field(NowHour, SpecField) of true -> NewDatetime = ecrontab_time_util:next_second(NowDatetime), case ecrontab_time_util:get_datetime_hour(NewDatetime) of NowHour -> {ok, NewDatetime}; _ -> next_time_only_one_hour(SpecField,NowDatetime) end; false -> next_time_only_one_hour(SpecField,NowDatetime) end; next_time_only_one(#spec.minute,Spec,NowDatetime) -> SpecField = Spec#spec.minute, NowMinute = ecrontab_time_util:get_datetime_minute(NowDatetime), case is_passed_spec_field(NowMinute, SpecField) of true -> NewDatetime = ecrontab_time_util:next_second(NowDatetime), case ecrontab_time_util:get_datetime_minute(NewDatetime) of NowMinute -> {ok, NewDatetime}; _ -> next_time_only_one_minute(SpecField,NowDatetime) end; false -> next_time_only_one_minute(SpecField,NowDatetime) end; next_time_only_one(#spec.second,Spec,NowDatetime) -> SpecField = Spec#spec.second, NowSecond = ecrontab_time_util:get_datetime_minute(NowDatetime), case is_passed_spec_field(NowSecond, SpecField) of true -> NewDatetime = ecrontab_time_util:next_second(NowDatetime), case ecrontab_time_util:get_datetime_second(NewDatetime) of NowSecond -> {ok, NewDatetime}; _ -> next_time_only_one_second(SpecField,NowDatetime) end; false -> next_time_only_one_second(SpecField,NowDatetime) end. next_time_only_one_year(SpecField,{{NowYear,_,_},_}) -> case SpecField#spec_field.type of ?SPEC_FIELD_TYPE_NUM -> NextYear = SpecField#spec_field.value, if NextYear > NowYear -> {ok, {{SpecField#spec_field.value,1,1},{0,0,0}}}; true -> {false, time_over} end; ?SPEC_FIELD_TYPE_LIST -> List = SpecField#spec_field.value, case find_next_in_list(NowYear,List) of false -> {false, time_over}; NextYear -> {ok, {{NextYear,1,1},{0,0,0}}} end end. next_time_only_one_month(SpecField,{{Y,NowMonth,_},_}) -> case SpecField#spec_field.type of ?SPEC_FIELD_TYPE_NUM -> NextMonth = SpecField#spec_field.value, if NextMonth > NowMonth -> {ok, {{Y,NextMonth,1},{0,0,0}}}; true -> {ok, {{Y+1,NextMonth,1},{0,0,0}}} end; ?SPEC_FIELD_TYPE_LIST -> List = SpecField#spec_field.value, case find_next_in_list(NowMonth,List) of false -> NextMonth = hd(List), {ok, {{Y+1,NextMonth,1},{0,0,0}}}; NextMonth -> {ok, {{Y,NextMonth,1},{0,0,0}}} end end. next_time_only_one_day(SpecField,{{Y,M,NowDay},_}) -> case SpecField#spec_field.type of ?SPEC_FIELD_TYPE_NUM -> NextDay = SpecField#spec_field.value, if NextDay > NowDay -> next_time_only_one_day_do(Y,M,NextDay,{0,0,0}); true -> case M of 12 -> next_time_only_one_day_do(Y+1,1,NextDay,{0,0,0}); _ -> next_time_only_one_day_do(Y,M+1,NextDay,{0,0,0}) end end; ?SPEC_FIELD_TYPE_LIST -> List = SpecField#spec_field.value, case find_next_in_list(NowDay,List) of false -> NextDay = hd(List), next_time_only_one_day_do(Y,M,NextDay,{0,0,0}); NextDay -> LastDay = calendar:last_day_of_the_month(Y,M), if LastDay < NextDay -> NextDay2 = hd(List), next_time_only_one_day_do(Y,M,NextDay2,{0,0,0}); true -> {ok, {{Y,M,NextDay},{0,0,0}}} end end end. next_time_only_one_day_do(Y,M,NextDay,Time) -> LastDay = calendar:last_day_of_the_month(Y,M), if LastDay < NextDay -> case M of 12 -> next_time_only_one_day_do(Y+1,1,NextDay,Time); _ -> next_time_only_one_day_do(Y,M+1,NextDay,Time) end; true -> {ok, {{Y,M,NextDay},Time}} end. next_time_only_one_week(SpecField,NowWeek,{Date,_}) -> Days = calendar:date_to_gregorian_days(Date), NewDays = case SpecField#spec_field.type of ?SPEC_FIELD_TYPE_NUM -> NextWeek = SpecField#spec_field.value, if NextWeek > NowWeek -> Days + NextWeek - NowWeek; true -> Days + (7 - (NowWeek - NextWeek)) end; ?SPEC_FIELD_TYPE_LIST -> List = SpecField#spec_field.value, case find_next_in_list(NowWeek,List) of false -> NextWeek = hd(List), Days + (7 - (NowWeek - NextWeek)); NextWeek -> Days + NextWeek - NowWeek end end, NewDate = calendar:gregorian_days_to_date(NewDays), {ok,{NewDate,{0,0,0}}}. next_time_only_one_hour(SpecField,{Date,{NowHour,_,_}}) -> DateTime = case SpecField#spec_field.type of ?SPEC_FIELD_TYPE_NUM -> NextHour = SpecField#spec_field.value, if NextHour > NowHour -> {Date,{NextHour,0,0}}; true -> ecrontab_time_util:next_day({Date,{NextHour,0,0}}) end; ?SPEC_FIELD_TYPE_LIST -> List = SpecField#spec_field.value, case find_next_in_list(NowHour,List) of false -> NextHour = hd(List), ecrontab_time_util:next_day({Date,{NextHour,0,0}}); NextHour -> {Date,{NextHour,0,0}} end end, {ok, DateTime}. next_time_only_one_minute(SpecField,{Date,{HH,NowMinute,_}}) -> DateTime = case SpecField#spec_field.type of ?SPEC_FIELD_TYPE_NUM -> NextMinute = SpecField#spec_field.value, if NextMinute > NowMinute -> {Date,{HH,NextMinute,0}}; true -> ecrontab_time_util:next_hour({Date,{HH,NextMinute,0}}) end; ?SPEC_FIELD_TYPE_LIST -> List = SpecField#spec_field.value, case find_next_in_list(NowMinute,List) of false -> NextMinute = hd(List), ecrontab_time_util:next_hour({Date,{HH,NextMinute,0}}); NextMinute -> {Date,{HH,NextMinute,0}} end end, {ok, DateTime}. next_time_only_one_second(SpecField,{Date,{HH,MM,NowSecond}}) -> DateTime = case SpecField#spec_field.type of ?SPEC_FIELD_TYPE_NUM -> NextSecond = SpecField#spec_field.value, if NextSecond > NowSecond -> {Date,{HH,MM,NextSecond}}; true -> ecrontab_time_util:next_minute({Date,{HH,MM,NextSecond}}) end; ?SPEC_FIELD_TYPE_LIST -> List = SpecField#spec_field.value, case find_next_in_list(NowSecond,List) of false -> NextSecond = hd(List), ecrontab_time_util:next_minute({Date,{HH,MM,NextSecond}}); NextSecond -> {Date,{HH,MM,NextSecond}} end end, {ok, DateTime}. %% ==================================================================== %% next_time_only_one end %% ==================================================================== find_next_in_list(_,[]) -> false; find_next_in_list(NowValue,[Value|_]) when NowValue Value; find_next_in_list(NowValue,[_|List]) -> find_next_in_list(NowValue,List). is_passed_spec_field(_,#spec_field{type=?SPEC_FIELD_TYPE_ANY}) -> true; is_passed_spec_field(Value,#spec_field{type=?SPEC_FIELD_TYPE_NUM,value=Value}) -> true; is_passed_spec_field(Value,#spec_field{type=?SPEC_FIELD_TYPE_LIST,value=List}) -> ordsets:is_element(Value, List); is_passed_spec_field(_,_) -> false.