-<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.135 2007/08/02 23:39:43 adunstan Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.136 2007/08/04 01:26:53 tgl Exp $ -->
 
 <chapter Id="runtime-config">
   <title>Server Configuration</title>
         When <varname>redirect_stderr</varname> is enabled, this parameter
         sets the file names of the created log files.  The value
         is treated as a <systemitem>strftime</systemitem> pattern,
-        so <literal>%</literal>-escapes
-        can be used to specify time-varying file names.
+        so <literal>%</literal>-escapes can be used to specify time-varying
+        file names.  (Note that if there are
+        any time-zone-dependent <literal>%</literal>-escapes, the computation
+        is done in the zone specified by <xref linkend="guc-log-timezone">.)
         If no <literal>%</literal>-escapes are present,
-        <productname>PostgreSQL</productname> will
-        append the epoch of the new log file's open time.  For example,
-        if <varname>log_filename</varname> were <literal>server_log</literal>, then the
-        chosen file name would be <literal>server_log.1093827753</literal>
+        <productname>PostgreSQL</productname> will append the epoch of the new
+        log file's creation time.  For example, if
+        <varname>log_filename</varname> were <literal>server_log</literal>,
+        then the chosen file name would be <literal>server_log.1093827753</>
         for a log starting at Sun Aug 29 19:02:33 2004 MST.
         This parameter can only be set in the <filename>postgresql.conf</>
         file or on the server command line.
             </row>
             <row>
              <entry><literal>%t</literal></entry>
-             <entry>Time stamp without milliseconds (no timezone either on Windows)</entry>
+             <entry>Time stamp without milliseconds</entry>
              <entry>no</entry>
             </row>
             <row>
             </row>
             <row>
              <entry><literal>%s</literal></entry>
-             <entry>Session start time stamp</entry>
+             <entry>Process start time stamp</entry>
              <entry>no</entry>
             </row>
             <row>
 
          The <literal>%c</> escape prints a quasi-unique session identifier,
          consisting of two 4-byte hexadecimal numbers (without leading zeros)
-         separated by a dot.  The numbers are the session start time and the
+         separated by a dot.  The numbers are the process start time and the
          process ID, so <literal>%c</> can also be used as a space saving way
          of printing those items.
        </para>
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-log-timezone" xreflabel="log_timezone">
+      <term><varname>log_timezone</varname> (<type>string</type>)</term>
+      <indexterm>
+       <primary><varname>log_timezone</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Sets the time zone used for timestamps written in the log.
+        Unlike <xref linkend="guc-timezone">, this value is cluster-wide,
+        so that all sessions will report timestamps consistently.
+        The default is <literal>unknown</>, which means to use whatever
+        the system environment specifies as the time zone.  See <xref
+        linkend="datatype-timezones"> for more information.
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line.
+       </para>
+      </listitem>
+     </varlistentry>
+
      </variablelist>
     </sect2>
    </sect1>
       <listitem>
        <para>
         Sets the time zone for displaying and interpreting time stamps.
-        The default is <literal>'unknown'</>, which means to use whatever
+        The default is <literal>unknown</>, which means to use whatever
         the system environment specifies as the time zone.  See <xref
-        linkend="datatype-datetime"> for more
+        linkend="datatype-timezones"> for more
         information.
        </para>
       </listitem>
 
-<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.205 2007/07/27 10:37:52 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.206 2007/08/04 01:26:53 tgl Exp $ -->
 
  <chapter id="datatype">
   <title id="datatype-title">Data Types</title>
         savings transition-date rules as well.  The recognized abbreviations
         are listed in the <literal>pg_timezone_abbrevs</> view (see <xref
         linkend="view-pg-timezone-abbrevs">).  You cannot set the
-        configuration parameter <xref linkend="guc-timezone"> using a time
+        configuration parameters <xref linkend="guc-timezone"> or
+        <xref linkend="guc-log-timezone"> using a time
         zone abbreviation, but you can use abbreviations in
         date/time input values and with the <literal>AT TIME ZONE</>
         operator.
         behavior of the C library function <literal>localtime()</>.  The
         default time zone is selected as the closest match among
         <productname>PostgreSQL</productname>'s known time zones.
+        (These rules are also used to choose the default value of
+        <xref linkend="guc-log-timezone">, if it is not specified.)
        </para>
       </listitem>
 
 
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.276 2007/08/01 22:45:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.277 2007/08/04 01:26:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
                     uint32 endLogId, uint32 endLogSeg);
 static void WriteControlFile(void);
 static void ReadControlFile(void);
-static char *str_time(time_t tnow);
+static char *str_time(pg_time_t tnow);
 static void issue_xlog_fsync(void);
 
 #ifdef WAL_DEBUG
 }
 
 static char *
-str_time(time_t tnow)
+str_time(pg_time_t tnow)
 {
    static char buf[128];
 
-   strftime(buf, sizeof(buf),
-            "%Y-%m-%d %H:%M:%S %Z",
-            localtime(&tnow));
+   pg_strftime(buf, sizeof(buf),
+               "%Y-%m-%d %H:%M:%S %Z",
+               pg_localtime(&tnow, log_timezone));
 
    return buf;
 }
    char       *backupidstr;
    XLogRecPtr  checkpointloc;
    XLogRecPtr  startpoint;
-   time_t      stamp_time;
+   pg_time_t   stamp_time;
    char        strfbuf[128];
    char        xlogfilename[MAXFNAMELEN];
    uint32      _logId;
        XLByteToSeg(startpoint, _logId, _logSeg);
        XLogFileName(xlogfilename, ThisTimeLineID, _logId, _logSeg);
 
-       /*
-        * We deliberately use strftime/localtime not the src/timezone
-        * functions, so that backup labels will consistently be recorded in
-        * the same timezone regardless of TimeZone setting.  This matches
-        * elog.c's practice.
-        */
-       stamp_time = time(NULL);
-       strftime(strfbuf, sizeof(strfbuf),
-                "%Y-%m-%d %H:%M:%S %Z",
-                localtime(&stamp_time));
+       /* Use the log timezone here, not the session timezone */
+       stamp_time = (pg_time_t) time(NULL);
+       pg_strftime(strfbuf, sizeof(strfbuf),
+                   "%Y-%m-%d %H:%M:%S %Z",
+                   pg_localtime(&stamp_time, log_timezone));
 
        /*
         * Check for existing backup label --- implies a backup is already
    text       *result;
    XLogRecPtr  startpoint;
    XLogRecPtr  stoppoint;
-   time_t      stamp_time;
+   pg_time_t   stamp_time;
    char        strfbuf[128];
    char        histfilepath[MAXPGPATH];
    char        startxlogfilename[MAXFNAMELEN];
    XLByteToSeg(stoppoint, _logId, _logSeg);
    XLogFileName(stopxlogfilename, ThisTimeLineID, _logId, _logSeg);
 
-   /*
-    * We deliberately use strftime/localtime not the src/timezone functions,
-    * so that backup labels will consistently be recorded in the same
-    * timezone regardless of TimeZone setting.  This matches elog.c's
-    * practice.
-    */
-   stamp_time = time(NULL);
-   strftime(strfbuf, sizeof(strfbuf),
-            "%Y-%m-%d %H:%M:%S %Z",
-            localtime(&stamp_time));
+   /* Use the log timezone here, not the session timezone */
+   stamp_time = (pg_time_t) time(NULL);
+   pg_strftime(strfbuf, sizeof(strfbuf),
+               "%Y-%m-%d %H:%M:%S %Z",
+               pg_localtime(&stamp_time, log_timezone));
 
    /*
     * Open the existing label file
 
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.120 2007/01/05 22:19:27 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.121 2007/08/04 01:26:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
             */
            if (doit)
            {
-               const char *curzone = pg_get_timezone_name(global_timezone);
+               const char *curzone = pg_get_timezone_name(session_timezone);
 
                if (curzone)
                    value = curzone;
            if (doit)
            {
                /* Save the changed TZ */
-               global_timezone = new_tz;
+               session_timezone = new_tz;
                HasCTZSet = false;
            }
        }
                                              IntervalPGetDatum(&interval)));
    }
    else
-       tzn = pg_get_timezone_name(global_timezone);
+       tzn = pg_get_timezone_name(session_timezone);
+
+   if (tzn != NULL)
+       return tzn;
+
+   return "unknown";
+}
+
+
+/*
+ * LOG_TIMEZONE
+ *
+ * For log_timezone, we don't support the interval-based methods of setting a
+ * zone, which are only there for SQL spec compliance not because they're
+ * actually useful.
+ */
+
+/*
+ * assign_log_timezone: GUC assign_hook for log_timezone
+ */
+const char *
+assign_log_timezone(const char *value, bool doit, GucSource source)
+{
+   char       *result;
+
+   if (pg_strcasecmp(value, "UNKNOWN") == 0)
+   {
+       /*
+        * UNKNOWN is the value shown as the "default" for log_timezone in
+        * guc.c.  We interpret it as being a complete no-op; we don't
+        * change the timezone setting.  Note that if there is a known
+        * timezone setting, we will return that name rather than UNKNOWN
+        * as the canonical spelling.
+        *
+        * During GUC initialization, since the timezone library isn't set
+        * up yet, pg_get_timezone_name will return NULL and we will leave
+        * the setting as UNKNOWN.  If this isn't overridden from the
+        * config file then pg_timezone_initialize() will eventually
+        * select a default value from the environment.
+        */
+       if (doit)
+       {
+           const char *curzone = pg_get_timezone_name(log_timezone);
+
+           if (curzone)
+               value = curzone;
+       }
+   }
+   else
+   {
+       /*
+        * Otherwise assume it is a timezone name, and try to load it.
+        */
+       pg_tz      *new_tz;
+
+       new_tz = pg_tzset(value);
+
+       if (!new_tz)
+       {
+           ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("unrecognized time zone name: \"%s\"",
+                           value)));
+           return NULL;
+       }
+
+       if (!tz_acceptable(new_tz))
+       {
+           ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("time zone \"%s\" appears to use leap seconds",
+                           value),
+                    errdetail("PostgreSQL does not support leap seconds.")));
+           return NULL;
+       }
+
+       if (doit)
+       {
+           /* Save the changed TZ */
+           log_timezone = new_tz;
+       }
+   }
+
+   /*
+    * If we aren't going to do the assignment, just return OK indicator.
+    */
+   if (!doit)
+       return value;
+
+   /*
+    * Prepare the canonical string to return.  GUC wants it malloc'd.
+    */
+   result = strdup(value);
+
+   return result;
+}
+
+/*
+ * show_log_timezone: GUC show_hook for log_timezone
+ */
+const char *
+show_log_timezone(void)
+{
+   const char *tzn;
+
+   tzn = pg_get_timezone_name(log_timezone);
 
    if (tzn != NULL)
        return tzn;
 
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.35 2007/08/02 23:39:44 adunstan Exp $
+ *   $PostgreSQL: pgsql/src/backend/postmaster/syslogger.c,v 1.36 2007/08/04 01:26:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 {
    char       *filename;
    int         len;
-   struct pg_tm *tm;
 
    filename = palloc(MAXPGPATH);
 
    if (strchr(Log_filename, '%'))
    {
        /* treat it as a strftime pattern */
-       tm = pg_localtime(×tamp, global_timezone);
-       pg_strftime(filename + len, MAXPGPATH - len, Log_filename, tm);
+       pg_strftime(filename + len, MAXPGPATH - len, Log_filename,
+                   pg_localtime(×tamp, log_timezone));
    }
    else
    {
    /*
     * The requirements here are to choose the next time > now that is a
     * "multiple" of the log rotation interval.  "Multiple" can be interpreted
-    * fairly loosely.  In this version we align to local time rather than
+    * fairly loosely.  In this version we align to log_timezone rather than
     * GMT.
     */
    rotinterval = Log_RotationAge * SECS_PER_MINUTE;    /* convert to seconds */
-   now = time(NULL);
-   tm = pg_localtime(&now, global_timezone);
+   now = (pg_time_t) time(NULL);
+   tm = pg_localtime(&now, log_timezone);
    now += tm->tm_gmtoff;
    now -= now % rotinterval;
    now += rotinterval;
 
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.134 2007/07/06 04:15:58 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.135 2007/08/04 01:26:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
    tm->tm_hour = 0;
    tm->tm_min = 0;
    tm->tm_sec = 0;
-   tz = DetermineTimeZoneOffset(tm, global_timezone);
+   tz = DetermineTimeZoneOffset(tm, session_timezone);
 
 #ifdef HAVE_INT64_TIMESTAMP
    result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
 
    GetCurrentDateTime(tm);
    time2tm(time, tm, &fsec);
-   tz = DetermineTimeZoneOffset(tm, global_timezone);
+   tz = DetermineTimeZoneOffset(tm, session_timezone);
 
    result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
 
 
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.181 2007/06/12 15:58:32 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.182 2007/08/04 01:26:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
            if (fmask & DTK_M(DTZMOD))
                return DTERR_BAD_FORMAT;
 
-           *tzp = DetermineTimeZoneOffset(tm, global_timezone);
+           *tzp = DetermineTimeZoneOffset(tm, session_timezone);
        }
    }
 
                after_isdst;
    int         res;
 
-   if (tzp == global_timezone && HasCTZSet)
+   if (tzp == session_timezone && HasCTZSet)
    {
        tm->tm_isdst = 0;       /* for lack of a better idea */
        return CTimeZone;
        tmp->tm_hour = tm->tm_hour;
        tmp->tm_min = tm->tm_min;
        tmp->tm_sec = tm->tm_sec;
-       *tzp = DetermineTimeZoneOffset(tmp, global_timezone);
+       *tzp = DetermineTimeZoneOffset(tmp, session_timezone);
        tm->tm_isdst = tmp->tm_isdst;
    }
 
 
 /* -----------------------------------------------------------------------
  * formatting.c
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.130 2007/06/29 01:51:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.131 2007/08/04 01:26:53 tgl Exp $
  *
  *
  *  Portions Copyright (c) 1999-2007, PostgreSQL Global Development Group
 
    do_to_timestamp(date_txt, fmt, &tm, &fsec);
 
-   tz = DetermineTimeZoneOffset(&tm, global_timezone);
+   tz = DetermineTimeZoneOffset(&tm, session_timezone);
 
    if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
        ereport(ERROR,
 
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.150 2007/02/27 23:48:08 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.151 2007/08/04 01:26:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
        time -= CTimeZone;
 
    if (!HasCTZSet && tzp != NULL)
-       tx = pg_localtime(&time, global_timezone);
+       tx = pg_localtime(&time, session_timezone);
    else
        tx = pg_gmtime(&time);
 
        result = NOEND_ABSTIME;
    else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
    {
-       tz = DetermineTimeZoneOffset(tm, global_timezone);
+       tz = DetermineTimeZoneOffset(tm, session_timezone);
        result = tm2abstime(tm, tz);
    }
    else
    gettimeofday(&tp, NULL);
    tt = (pg_time_t) tp.tv_sec;
    pg_strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%06d %Y %Z",
-               pg_localtime(&tt, global_timezone));
+               pg_localtime(&tt, session_timezone));
    snprintf(buf, sizeof(buf), templ, tp.tv_usec);
 
    len = VARHDRSZ + strlen(buf);
 
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.180 2007/07/18 03:13:13 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.181 2007/08/04 01:26:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
    if ((Timestamp) utime == dt)
    {
        struct pg_tm *tx = pg_localtime(&utime,
-                                 attimezone ? attimezone : global_timezone);
+                                 attimezone ? attimezone : session_timezone);
 
        tm->tm_year = tx->tm_year + 1900;
        tm->tm_mon = tx->tm_mon + 1;
            if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
                tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
 
-           tz = DetermineTimeZoneOffset(tm, global_timezone);
+           tz = DetermineTimeZoneOffset(tm, session_timezone);
 
            if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
                ereport(ERROR,
            julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
            j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
 
-           tz = DetermineTimeZoneOffset(tm, global_timezone);
+           tz = DetermineTimeZoneOffset(tm, session_timezone);
 
            if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0)
                ereport(ERROR,
        }
 
        if (redotz)
-           tz = DetermineTimeZoneOffset(tm, global_timezone);
+           tz = DetermineTimeZoneOffset(tm, session_timezone);
 
        if (tm2timestamp(tm, fsec, &tz, &result) != 0)
            ereport(ERROR,
                                (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                 errmsg("timestamp out of range")));
 
-                   tz = DetermineTimeZoneOffset(tm, global_timezone);
+                   tz = DetermineTimeZoneOffset(tm, session_timezone);
 
                    if (tm2timestamp(tm, fsec, &tz, ×tamptz) != 0)
                        ereport(ERROR,
                    (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                     errmsg("timestamp out of range")));
 
-       tz = DetermineTimeZoneOffset(tm, global_timezone);
+       tz = DetermineTimeZoneOffset(tm, session_timezone);
 
        if (tm2timestamp(tm, fsec, &tz, &result) != 0)
            ereport(ERROR,
 
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.191 2007/08/02 23:39:44 adunstan Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.192 2007/08/04 01:26:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
                break;
            case 'm':
                {
-                   /*
-                    * Note: for %m, %t, and %s we deliberately use the C
-                    * library's strftime/localtime, and not the equivalent
-                    * functions from src/timezone.  This ensures that all
-                    * backends will report log entries in the same timezone,
-                    * namely whatever C-library setting they inherit from the
-                    * postmaster.  If we used src/timezone then local
-                    * settings of the TimeZone GUC variable would confuse the
-                    * log.
-                    */
-                   time_t      stamp_time;
+                   struct timeval tv;
+                   pg_time_t   stamp_time;
                    char        strfbuf[128],
                                msbuf[8];
-                   struct timeval tv;
 
                    gettimeofday(&tv, NULL);
-                   stamp_time = tv.tv_sec;
+                   stamp_time = (pg_time_t) tv.tv_sec;
 
-                   strftime(strfbuf, sizeof(strfbuf),
-                   /* leave room for milliseconds... */
-                   /* Win32 timezone names are too long so don't print them */
-#ifndef WIN32
-                            "%Y-%m-%d %H:%M:%S     %Z",
-#else
-                            "%Y-%m-%d %H:%M:%S     ",
-#endif
-                            localtime(&stamp_time));
+                   pg_strftime(strfbuf, sizeof(strfbuf),
+                               /* leave room for milliseconds... */
+                               "%Y-%m-%d %H:%M:%S     %Z",
+                               pg_localtime(&stamp_time, log_timezone));
 
                    /* 'paste' milliseconds into place... */
                    sprintf(msbuf, ".%03d", (int) (tv.tv_usec / 1000));
                break;
            case 't':
                {
-                   time_t      stamp_time = time(NULL);
+                   pg_time_t   stamp_time = (pg_time_t) time(NULL);
                    char        strfbuf[128];
 
-                   strftime(strfbuf, sizeof(strfbuf),
-                   /* Win32 timezone names are too long so don't print them */
-#ifndef WIN32
-                            "%Y-%m-%d %H:%M:%S %Z",
-#else
-                            "%Y-%m-%d %H:%M:%S",
-#endif
-                            localtime(&stamp_time));
+                   pg_strftime(strfbuf, sizeof(strfbuf),
+                               "%Y-%m-%d %H:%M:%S %Z",
+                               pg_localtime(&stamp_time, log_timezone));
                    appendStringInfoString(buf, strfbuf);
                }
                break;
            case 's':
                {
+                   pg_time_t   stamp_time = (pg_time_t) MyStartTime;
                    char        strfbuf[128];
 
-                   strftime(strfbuf, sizeof(strfbuf),
-                   /* Win32 timezone names are too long so don't print them */
-#ifndef WIN32
-                            "%Y-%m-%d %H:%M:%S %Z",
-#else
-                            "%Y-%m-%d %H:%M:%S",
-#endif
-                            localtime(&MyStartTime));
+                   pg_strftime(strfbuf, sizeof(strfbuf),
+                               "%Y-%m-%d %H:%M:%S %Z",
+                               pg_localtime(&stamp_time, log_timezone));
                    appendStringInfoString(buf, strfbuf);
                }
                break;
 
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.408 2007/08/01 22:45:09 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.409 2007/08/04 01:26:54 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
 static char *server_version_string;
 static int server_version_num;
 static char *timezone_string;
+static char *log_timezone_string;
 static char *timezone_abbreviations_string;
 static char *XactIsoLevel_string;
 static char *data_directory;
        "", NULL, NULL
    },
 
+   {
+       {"log_timezone", PGC_SIGHUP, LOGGING_WHAT,
+           gettext_noop("Sets the time zone to use in log messages."),
+           NULL
+       },
+       &log_timezone_string,
+       "UNKNOWN", assign_log_timezone, show_log_timezone
+   },
 
    {
        {"DateStyle", PGC_USERSET, CLIENT_CONN_LOCALE,
 
 #log_temp_files = -1           # Log temporary files equal or larger
                    # than specified number of kilobytes.
                    # -1 disables;  0 logs all temp files
+#log_timezone = unknown            # actually, defaults to TZ 
+                   # environment setting
 
 #---------------------------------------------------------------------------
 # RUNTIME STATISTICS
 
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/variable.h,v 1.29 2007/01/05 22:19:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/variable.h,v 1.30 2007/08/04 01:26:54 tgl Exp $
  */
 #ifndef VARIABLE_H
 #define VARIABLE_H
 extern const char *assign_timezone(const char *value,
                bool doit, GucSource source);
 extern const char *show_timezone(void);
+extern const char *assign_log_timezone(const char *value,
+               bool doit, GucSource source);
+extern const char *show_log_timezone(void);
 extern const char *assign_XactIsoLevel(const char *value,
                    bool doit, GucSource source);
 extern const char *show_XactIsoLevel(void);
 
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/include/pgtime.h,v 1.15 2007/01/05 22:19:50 momjian Exp $
+ *   $PostgreSQL: pgsql/src/include/pgtime.h,v 1.16 2007/08/04 01:26:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 extern pg_tz *pg_tzenumerate_next(pg_tzenum *dir);
 extern void pg_tzenumerate_end(pg_tzenum *dir);
 
-extern pg_tz *global_timezone;
+extern pg_tz *session_timezone;
+extern pg_tz *log_timezone;
 
 /* Maximum length of a timezone name (not including trailing null) */
 #define TZ_STRLEN_MAX 255
 
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.51 2007/05/31 15:13:06 petere Exp $
+ *   $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.52 2007/08/04 01:26:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "utils/guc.h"
 #include "utils/hsearch.h"
 
-/* Current global timezone */
-pg_tz     *global_timezone = NULL;
+/* Current session timezone (controlled by TimeZone GUC) */
+pg_tz     *session_timezone = NULL;
+
+/* Current log timezone (controlled by log_timezone GUC) */
+pg_tz     *log_timezone = NULL;
 
 
 static char tzdir[MAXPGPATH];
                              const char *fname, int fnamelen,
                              char *canonname, int canonnamelen);
 static const char *identify_system_timezone(void);
-static const char *select_default_timezone(void);
-static bool set_global_timezone(const char *tzname);
+static pg_tz *get_pg_tz_for_zone(const char *tzname);
+static pg_tz *select_default_timezone(void);
 
 
 /*
 
 
 /*
- * Set the global timezone. Verify that it's acceptable first.
+ * Get a pg_tz struct for the given timezone name.  Returns NULL if name
+ * is invalid or not an "acceptable" zone.
  */
-static bool
-set_global_timezone(const char *tzname)
+static pg_tz *
+get_pg_tz_for_zone(const char *tzname)
 {
-   pg_tz      *tznew;
+   pg_tz      *tz;
 
    if (!tzname || !tzname[0])
-       return false;
+       return NULL;
 
-   tznew = pg_tzset(tzname);
-   if (!tznew)
-       return false;
+   tz = pg_tzset(tzname);
+   if (!tz)
+       return NULL;
 
-   if (!tz_acceptable(tznew))
-       return false;
+   if (!tz_acceptable(tz))
+       return NULL;
 
-   global_timezone = tznew;
-   return true;
+   return tz;
 }
 
 /*
- * Identify a suitable default timezone setting based on the environment,
- * and make it active.
+ * Identify a suitable default timezone setting based on the environment.
  *
  * We first look to the TZ environment variable.  If not found or not
  * recognized by our own code, we see if we can identify the timezone
  * from the behavior of the system timezone library.  When all else fails,
  * fall back to GMT.
  */
-static const char *
+static pg_tz *
 select_default_timezone(void)
 {
-   const char *def_tz;
+   pg_tz      *def_tz;
 
-   def_tz = getenv("TZ");
-   if (set_global_timezone(def_tz))
+   def_tz = get_pg_tz_for_zone(getenv("TZ"));
+   if (def_tz)
        return def_tz;
 
-   def_tz = identify_system_timezone();
-   if (set_global_timezone(def_tz))
+   def_tz = get_pg_tz_for_zone(identify_system_timezone());
+   if (def_tz)
        return def_tz;
 
-   if (set_global_timezone("GMT"))
-       return "GMT";
+   def_tz = get_pg_tz_for_zone("GMT");
+   if (def_tz)
+       return def_tz;
 
    ereport(FATAL,
            (errmsg("could not select a suitable default timezone"),
  *
  * This is called after initial loading of postgresql.conf.  If no TimeZone
  * setting was found therein, we try to derive one from the environment.
+ * Likewise for log_timezone.
  */
 void
 pg_timezone_initialize(void)
 {
-   /* Do we need to try to figure the timezone? */
+   pg_tz      *def_tz = NULL;
+
+   /* Do we need to try to figure the session timezone? */
    if (pg_strcasecmp(GetConfigOption("timezone"), "UNKNOWN") == 0)
    {
-       const char *def_tz;
-
        /* Select setting */
        def_tz = select_default_timezone();
+       session_timezone = def_tz;
+       /* Tell GUC about the value. Will redundantly call pg_tzset() */
+       SetConfigOption("timezone", pg_get_timezone_name(def_tz),
+                       PGC_POSTMASTER, PGC_S_ARGV);
+   }
+
+   /* What about the log timezone? */
+   if (pg_strcasecmp(GetConfigOption("log_timezone"), "UNKNOWN") == 0)
+   {
+       /* Select setting, but don't duplicate work */
+       if (!def_tz)
+           def_tz = select_default_timezone();
+       log_timezone = def_tz;
        /* Tell GUC about the value. Will redundantly call pg_tzset() */
-       SetConfigOption("timezone", def_tz, PGC_POSTMASTER, PGC_S_ARGV);
+       SetConfigOption("log_timezone", pg_get_timezone_name(def_tz),
+                       PGC_POSTMASTER, PGC_S_ARGV);
    }
 }