Time library: Sperate different times of day

Hi guys,

I'm designing a power meter interface to calculate instantaneous consumption, total energy consumed, etc.

What I'm having trouble implementing is time of day separation. For example, to use a chaper night rate tariff. I have been using the time library and allarms, but I realized if the arduino is switched off it gets confused on which tarrif to start.

Is there a way to handle different conditions for a time period rather than an 'alarm'?

Thanks

Sure, check the time in an if statement and if it is between whatever two different times then do whichever action.

casemod:
Is there a way to handle different conditions for a time period rather than an ‘alarm’?

If you use a time library that privides a Unix timestamp (seconds since 1.1.1970) you can easily get “seconds since midnight” from that.

Perhaps similar:

unsigned long timestamp= RTC.now(); // get Unix time / local time from time library
unsigned long secsToday= timestamp%86400L; // calculate seconds since midnight
boolean dayTime= (secsToday>=6*3600L) && (secsToday<18*3600L); daytime 6:00-18:00

Actual code depends on the library you are using.
And on the hours you want to be dayTime hours.

Delta_G:
Sure, check the time in an if statement and if it is between whatever two different times then do whichever action.

How so? I haven't found a pattern that returns true or false under all conditions.

Say I have off peak between 2330 and 0630. So I test if 0030 time is larger than 2330 or 0030 smaller than 0630. They should both return true. I could use an and statement.

Now assume the off-peak starts at 0000 and finishes at 0700. So I test if, for example, 0030 is larger than 0000. It is. But its still less than 0700 so I cant use an and statement.

I was thinking in a way to create an array with all the minutes within the off peak hours. For example, between 2330 and 0630 it would be anything from 0 to 390 and from 1410 to 1440. So I would just have to compare the actual minute with the list of minutes. But how do I generate all the values so I can compare them?

Or perhaps I'm missing something really simple...

A quick and dirty way you could do this is to keep all intervals on the same day.

So instead of testing if now is between 2330 and 0630, test if now is between 2330 and 2359 or between 0000 and 0630.

Another approach (and something I have done in a project) is to convert the times you want to test against (2330, say) into their absolute time today.

Put another way, if today is 5 October, you could create a timestamp variable for 2330 on 5 October. You can then create another timestamp for 0630 on 6 October.

Then you can compare now with those two times.

When it is the next day, you create a 2330 on 6 October timestamp and so on.

Etzeitet:
A quick and dirty way you could do this is to keep all intervals on the same day.

So instead of testing if now is between 2330 and 0630, test if now is between 2330 and 2359 or between 0000 and 0630.

Define "between". (Is the number 10 "between" 1 and 10?)
And don't use leading zeros in code unless you know what leading zeros do (hint: probably not what you want).

Another approach (and something I have done in a project) is to convert the times you want to test against (2330, say) into their absolute time today.

Put another way, if today is 5 October, you could create a timestamp variable for 2330 on 5 October. You can then create another timestamp for 0630 on 6 October.

Then you can compare now with those two times.

What happens if you try this at, say, 04:00 on 5 October?

Anyway, if you are trying to test for "between 23:30 and 06:30", I would rewrite this as "either earlier than 06:30 or later than 23:30" (possibly tweaking this a bit to include the exact times 06:30 and/or 23:30). Here's a diagram. Does this help?

    00  02  04  06  08  10  12  14  16  18  20  22  
      01  03  05  07  09  11  13  15  17  19  21  23
 IN @@@@@@@@@@@@@                                  @ IN
OUT              XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX  OUT

I think it might be simpler to use some check boxes with half an hour intervals in a similar way to a mechanical timer. This way I could compare only 48 results. But a way to automize this would be nice to have so as to avoid having to read 48 extra variables from the SD card.

Using different days would just add up to the confusion.

Odometer, later than 23h30 would only work untill midnight and earlier than 6h60 would only work after midnight. This would require an or statment otherwise the condition would always be true.

This would be fine, still the problem is when the date is changed to 00h00 and 06h30. Here an and statment is required (later than 00h00 AND earlier than 06h30), so these two would not be compatible.

Etzeitet:
So instead of testing if now is between 2330 and 0630, test if now is between 2330 and 2359 or between 0000 and 0630.

I hope, when writing numbers in your source code, you write “630” for a dezimal number and not “0630”.

The 0-prefix means “octal number” for the compiler, so:
0630 (octal) is = 682 + 381 + 0+80 = 408 (decimal)
0000 (octal) is 0 decimal
2330 and 2359 are decimal

So take care what you write in your source code. Decimal numbers start with number 1…9 only, and numbers starting with 0 are octal numbers in C/C++.

jurs, odometer:

That sentence is in English, not C or C++. I could have just as easily said "between 11:30 PM and 6:30 AM". I apologise for any confusion. I figured the OP would represent the times in the format most appropriate for his sketch.

casemod:
Odometer, later than 23h30 would only work untill midnight and earlier than 6h60 would only work after midnight. This would require an or statment otherwise the condition would always be true.

This would be fine, still the problem is when the date is changed to 00h00 and 06h30. Here an and statment is required (later than 00h00 AND earlier than 06h30), so these two would not be compatible.

I think this would work (though maybe it is too fancy):

if (((now>=startTime)+(now<endTime)+(startTime>endTime))==2) {

  // if we're in here, then the time is WITHIN the specified interval
  
}

I am building this from three conditions:

Condition #1: (now>=startTime)
Condition #2: (now<endTime)
Condition #3: (startTime>endTime)

What the + signs do is add up how many of the conditions are true.
What the ==2 does is check that exactly two (any two will do) of the conditions are true.

casemod:
How so? I haven’t found a pattern that returns true or false under all conditions.

You can check anything you want if you put a little thought into it.

This is what I use in one program, all times are converted to seconds after midnight and the checks look like this: (getTime is a function that converts times to seconds from midnight. That’s not the importent part)

boolean DoseSchedule::isInRange(TimeOfDay _val) {
	//  Determines if the time of day argument is within the dosing window
	//  ie is between start and end times inclusive.

	if (start_time.getTime() < end_time.getTime()) {
		return ((_val.getTime() >= start_time.getTime())
				&& (_val.getTime() <= end_time.getTime()));  // simple case
	} else if (start_time.getTime() > end_time.getTime()) {
		return ((_val.getTime() >= start_time.getTime())
				|| (_val.getTime() <= end_time.getTime())); // accounts for midnight rollover
	} else
		return (1);   //  if start_time = end_time, then it's always in range.
}

So you have a start time and an end time for your range. IF the start time is less than the end time then the range doesn’t wrap around midnight and it is trivially easy to check that the time in question is greater than the start AND less than the end.

If the end time is less than the start time that implies that the interval covers midnight, say an interval from 23:00 to 05:00. In this case you are checking just the opposite, that the time in question is NOT between those two. In this case you are in the interval if the time in question is greater than the start time OR less than the end time.