bug-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Location of utility functions.


From: Sam Roberts
Subject: Re: Location of utility functions.
Date: Sat, 16 Jun 2001 13:36:52 -0400
User-agent: Mutt/1.3.16i

Quoting Sergey Poznyakoff <address@hidden>, who wrote:
> Bonjour,

Allo Segey, et ou est tu a le monde? 3 hours east of Paris, I take
it...

> A couple of thoughts about mktime() and the timezone problem. I have

> [ summary: mktime() always assumes that gmtoff is wrong, and that the
  tm is in the local timezone. ]

That appears to be true here, as well. I just spent some time messing
around, trying to understand how time is handled with the ANSI
functions, and I've come to the conclusion "not well".

What I see is (more for my benefit, probably):

- time_t is always UTC, seconds since the epoch. ok.

- time_t can be mapped to struct tm, two ways:

  - localtime(), tm in timezone of TZ, tz fields in tm are filled out
  - gmtime(), tm in UTC, tz fields filled out. This is useless, who
    cares what day of the week 1AM is in London?

  So, the only way to get a tm in an arbitrary timezone is
  to set the TZ environment variable.

- a tm can be mapped to time_t only one way, by mktime().

  So, mktime() is forced to assume that tm's tz fields are invalid,
  it clobbers them and sets them to the timezone specified in TZ.

  This is perfect if tm came from localtime(), but not so great
  otherwise.

  So, if the tm is actually correct, including the tz fields, but
  not in our local TZ, then you have some problems.

It looks like figureing out our offset in seconds from UTC, and
after converting tm to time_t with mktime(), adjusting the time_t
is the only way you can do this. I was fairly surprised.

Anyhow, I've a few suggestions:

What is useful to do is convert tm to time_t, assuming tm's tz
fields (and possibly others) need to be set correctly in our local
TZ.  mktime() does this.

Also useful is to convert tm to time_t assuming that the tm is
in a particular timzone, say, the one that it's tz fields are set
to...

How about I:

- Rename mu_mktime to mu_tm2time(struct tm* tmptr).
- Have mu_tm2time() assume that the tz fields are correct, and NOT
  trash them.

time_t mu_tm2time(struct tm* tmptr)
{
# define MU_INVALID_TIMEZONE (25 * 60 * 60)
  static int mu_timezone = MU_INVALID_TIMEZONE;

  struct tm tm = *tmptr;

/* We don't want to recalculat mu_timezone if we live in London.

   Or, maybe we should recalculate each time, what if TZ changed?

   <rant>
   It's always bugged me how hard it is to change system settings
   like this, I like the conf strings. If a process set's TZ, it
   pegs it down for itself and it's children, but it doesn't, the
   computer can move (imagine that?) to a new timezone without
   having to be rebooted, or every app rewritten to allow it's
   personal concept of timezone to be changed. This was a huge pain
   on embedded systems projects I worked on.
   </rant>
*/
  if(mu_timezone == MU_INVALID_TIMEZONE)
  {
     mu_timezone == mu_utc_offset();
  }

  return mktime(&tm) - mu_timezone + tmptr->tm_gmtoff;
}

time_t mu_utc_offset()
{
  struct tm *tm;
  time_t t = 0;
  tm = gmtime(&t);
  return mktime(tm);
}

/* and for bonus points, I'd like to write this: */
struct tm* mu_time2tm(time_t t, struct tm* tmptr, int gmtoff)
{
  save TZ
  set TZ;
  localtime();
  restore TZ;

  return tmptr;
}

It's not clear to me from stareing at the env API functions if
I can do this safely, i.e. without leaking memory.

> struct tm. So I have implemented the function mu_mktime(struct *tm,
> int tz), its source is mailbox/mu_mktime.c (I guess your proposition
> for it to be mutil_mktime is great, I have just finished commiting the
> changes when I got your letter :^). I would also propose that

Yes, I actually saw the changes and started playing around trying
to clarify to myself how this stuff was supposed to work before seeing
your mail!

> parse822_date_time(), which also suffers from timezone problem, be:
> 
> int parse822_date_time(const char** p, const char* e, struct tm* tm, int *tz);
> 
> and that it return the timezone in the location pointed to by its last
> argument. To do this it would suffice to:

What I want to do is:

struct tm tm;

parse822_date_time(..., &tm);

t = mu_tm2time(&tm);

mu_parse_ctime(..., &tm);

/* ctime in a mbox From_ appears to be in UTC, is that so?
 If it was in local time, do:

tm.tm_gmtoff = mu_utc_offset();
*/

t = mu_tm2time(&tm);


BUT...

I have a feeling that you will tell me that struct tm doesn't have
a tm_gmtoff portably...

If that's true, then I'll buckle to necessity, timezone offset will
have to be carried around outside of struct tm, so I'll add the
int* timezone arg you suggest to parse822_date_time().

Sam

> -int parse822_date_time(const char** p, const char* e, struct tm* tm)
> +int parse822_date_time(const char** p, const char* e, struct tm* tm, int 
> *tzp)

> > So where should utility functions that will be exposed to the user
> > of mailbox go? I'd suggest mailbox/mutil.c, with corresponding header
> > files, and mutil_*() as functions names, to avoid colliding with imap4d/
> > util.c.
> <..snip..>
> > Anybody want to make an executive decision on this, or have a comment?
> 
> I guess it is a good idea. Let Alain give his verdict :^)

-- 
Sam Roberts <address@hidden> (Vivez sans temps mort!)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]