To create new wiki account, please join us on #znc at Libera.Chat and ask admins to create a wiki account for you. You can say thanks to spambots for this inconvenience.

Timestamps: Difference between revisions

From ZNC
Jump to navigation Jump to search
Gromit (talk | contribs)
As suggested by girst on IRC: add notice that IRSSI now supports show_server_time
 
(13 intermediate revisions by 4 users not shown)
Line 1: Line 1:
== Usage ==
= Usage =
 
If you have a modern client which supports <code>server-time</code> capability, timestamps are automatically shown correctly.
Otherwise, one of scripts below might help. But in that case consider upgrading your client instead.
 
== Instructions for ancient clients ==
 
If you want real timestamps you should use these settings for your user:
If you want real timestamps you should use these settings for your user:


Line 12: Line 18:
strftime arguments can be used for the timestamps, more details and arguments can be found at opengroup.org[http://opengroup.org/onlinepubs/007908799/xsh/strftime.html].
strftime arguments can be used for the timestamps, more details and arguments can be found at opengroup.org[http://opengroup.org/onlinepubs/007908799/xsh/strftime.html].


   %a the locale's abbreviated weekday name.  
   %a - the locale's abbreviated weekday name.  
   %A - the locale's full weekday name.  
   %A - the locale's full weekday name.  
   %b - the locale's abbreviated month name.  
   %b - the locale's abbreviated month name.  
Line 21: Line 27:
   %D - same as %m/%d/%y.  
   %D - same as %m/%d/%y.  
   %e - the day of the month as a decimal number [1,31]; a single digit is preceded by a space.  
   %e - the day of the month as a decimal number [1,31]; a single digit is preceded by a space.  
  %f - sub-second, e.g. %3f is number of milliseconds (the default), and %6f is number of microseconds. (since ZNC 1.7.0)
   %h - same as %b.  
   %h - same as %b.  
   %H - the hour (24-hour clock) as a decimal number [00,23].  
   %H - the hour (24-hour clock) as a decimal number [00,23].  
Line 50: Line 57:
== Scripts ==
== Scripts ==
=== KVIrc ===
=== KVIrc ===
This script '''requires''' this settings in your <User> section:
'''Notice''': last KVIrc from SVN supports <code>server-time</code>, no special script needed.
 
=== Instructions for ancient KVIrc ===
 
This script '''requires''' these settings for your user:


  TimestampFormat = {%H:%M:%S}
  TimestampFormat = {%H:%M:%S}
Line 60: Line 71:
  event(OnWallops,zncid)
  event(OnWallops,zncid)
  {
  {
  %timefront = $str.lefttofirst($3,$char(32))
  %timefront = $str.lefttofirst($3,$char(32))
  %timeappend = $str.rightfromlast($3,$char(32))
  %timeappend = $str.rightfromlast($3,$char(32))
 
 
  if($str.matchnocase(\{**\:**\:**\},%timefront))
  if($str.matchnocase(\{**\:**\:**\},%timefront))
Line 70: Line 78:
  %time = %timefront
  %time = %timefront
  %msg = $str.rightfromfirst($3,\})
  %msg = $str.rightfromfirst($3,\})
#echo %timefront front
  } else {
  } else {
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
Line 76: Line 83:
  %time = %timeappend
  %time = %timeappend
  %msg = $str.lefttofirst($3,\{)
  %msg = $str.lefttofirst($3,\{)
#echo %timeappend append
  }
  }
  }
  }
 
 
  if($str.matchnocase(\{**\:**\:**\},%time))
  if($str.matchnocase(\{**\:**\:**\},%time))
Line 87: Line 92:
  halt
  halt
  }
  }
   
   
  event(OnServerNotice,zncid)
  event(OnServerNotice,zncid)
Line 99: Line 103:
  {
  {
  %outchan = %con
  %outchan = %con
#echo -w=%outchan $0 $3 %outchan
  break;
  break;
  } else {
  } else {
Line 111: Line 114:
  }
  }
  }
  }
  %timefront = $str.lefttofirst($1,$char(32))
  %timefront = $str.lefttofirst($1,$char(32))
  %timeappend = $str.rightfromlast($1,$char(32))
  %timeappend = $str.rightfromlast($1,$char(32))
Line 118: Line 122:
  %time = %timefront
  %time = %timefront
  %msg = $str.rightfromfirst($1,\})
  %msg = $str.rightfromfirst($1,\})
#echo %timefront front
  } else {
  } else {
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
Line 124: Line 127:
  %time = %timeappend
  %time = %timeappend
  %msg = $str.lefttofirst($1,\{)
  %msg = $str.lefttofirst($1,\{)
#echo %timeappend append
  }
  }
  }
  }
Line 145: Line 147:
  {
  {
  %outchan = %chan[%x]
  %outchan = %chan[%x]
#echo -w=%outchan $0 $3 %outchan
  break;
  break;
  } else {
  } else {
Line 160: Line 161:
  %timefront = $str.lefttofirst($3,$char(32))
  %timefront = $str.lefttofirst($3,$char(32))
  %timeappend = $str.rightfromlast($3,$char(32))
  %timeappend = $str.rightfromlast($3,$char(32))
 
 
  if($str.matchnocase(\{**\:**\:**\},%timefront))
  if($str.matchnocase(\{**\:**\:**\},%timefront))
Line 166: Line 166:
  %time = %timefront
  %time = %timefront
  %msg = $str.rightfromfirst($3,\})
  %msg = $str.rightfromfirst($3,\})
#echo %timefront front
  } else {
  } else {
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
Line 172: Line 171:
  %time = %timeappend
  %time = %timeappend
  %msg = $str.lefttofirst($3,\{)
  %msg = $str.lefttofirst($3,\{)
#echo %timeappend append
  }
  }
  }
  }
 
 
  if($str.matchnocase(\{**\:**\:**\},%time))
  if($str.matchnocase(\{**\:**\:**\},%time))
Line 193: Line 190:
  %time = %timefront
  %time = %timefront
  %msg = $str.rightfromfirst($3,\})
  %msg = $str.rightfromfirst($3,\})
#echo %timefront front
  } else {
  } else {
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
Line 199: Line 195:
  %time = %timeappend
  %time = %timeappend
  %msg = $str.lefttofirst($3,\{)
  %msg = $str.lefttofirst($3,\{)
#echo %timeappend append
  }
  }
  }
  }
Line 222: Line 217:
  %time = %timefront
  %time = %timefront
  %msg = $str.rightfromfirst($3,\})
  %msg = $str.rightfromfirst($3,\})
#echo %timefront front
  } else {
  } else {
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
Line 228: Line 222:
  %time = %timeappend
  %time = %timeappend
  %msg = $str.lefttofirst($3,\{)
  %msg = $str.lefttofirst($3,\{)
#echo %timeappend append
  }
  }
  }
  }
Line 271: Line 264:
  %time = %timefront
  %time = %timefront
  %msg = $str.rightfromfirst($4,\})
  %msg = $str.rightfromfirst($4,\})
#echo %timefront front
  } else {
  } else {
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
  if($str.matchnocase(\{**\:**\:**\},%timeappend))
Line 277: Line 269:
  %time = %timeappend
  %time = %timeappend
  %msg = $str.lefttofirst($4,\{)
  %msg = $str.lefttofirst($4,\{)
#echo %timeappend append
  }
  }
  }
  }
Line 284: Line 275:
  if($str.matchnocase(\{**\:**\:**\},%time))
  if($str.matchnocase(\{**\:**\:**\},%time))
  {
  {
#%time = $date([H:M:S])
  echo -n -i=$msgtype(Action) $k($option(uinttimestampforeground))%time$k $0 %msg
  echo -n -i=$msgtype(Action) $k($option(uinttimestampforeground))%time$k $0 %msg
#echo $0 $3
  halt
  halt
  }
  }
Line 293: Line 282:


=== mIRC ===
=== mIRC ===
This script '''requires''' these settings in the <User *> section of your config file:
'''Notice''': mIRC supports <code>server-time</code> since 7.33, no special script needed.
 
=== Instructions for ancient mIRC ===
 
This script '''requires''' these settings for your user:


  TimestampFormat = [%H:%M:%S]
  TimestampFormat = [%H:%M:%S]
Line 471: Line 464:
  }
  }


=== irssi ===
'''Notice''': irssi supports <code>server-time</code> since 1.3, just set <code>/set show_server_time on</code>. For details refer to [https://irssi.org/documentation/settings/#show-server-time the settings documentation].
Go to https://scripts.irssi.org and install the '''server_time.pl''' script. Note that you must connect to ZNC while the script is already loaded in order for it to work (loading it after you've connected will do nothing).


=== irssi ===
=== WeeChat ===
This script '''requires''' these settings in the <User *> section of your config file:
'''Notice''': WeeChat supports <code>server-time</code> since 0.4.0, no special script needed.
 
But if you don't want to upgrade, you can try [http://www.weechat.org/files/scripts/unofficial/znc-playback.py znc-playback.py]
 
=== Other clients ===
Check documentation for your client, maybe it supports <code>server-time</code> too.
 
Clients which don't support <code>server-time</code> will just show the playback like this:
 
[08:44:30] Goldfish [monkey@2001:db8:a22c:67f::1] joined #unicorns
[08:44:30] Channel topic: O_o
[08:44:30] Topic set by Romeo!~opossum@2001:db8:451:eea6:5574:af2e:46:fe61 on Mon Mar 24 19:31:45 2014
[08:44:30] <***> Buffer Playback...
[08:44:30] <Rusty> [24 Jan 2015, 11:09:00] ah, the subfolder
[08:44:30] <Rusty> [24 Jan 2015, 11:09:00] meh
[08:44:30] <jor> [24 Jan 2015, 11:10:07] still not found
[08:44:30] <***> Playback Complete.
 
In this example the following settings are used:


TimestampFormat = [%H:%M:%S]
  AppendTimestamp = false
  AppendTimestamp = false
  PrependTimestamp = true
  PrependTimestamp = true
TimestampFormat = [%d %b %Y, %H:%M:%S]


Otherwise you have to adjust the regex pattern in the script that grabs the timestamp.
It feels less integrated with client, but it's not very harmful.
 
Download the script from: http://cba.si/stuff/znc_timestamp.pl
 
Put it into ~/.irssi/scripts, then '''/script load znc_timestamp''' .

Latest revision as of 15:45, 2 July 2023

Usage

If you have a modern client which supports server-time capability, timestamps are automatically shown correctly. Otherwise, one of scripts below might help. But in that case consider upgrading your client instead.

Instructions for ancient clients

If you want real timestamps you should use these settings for your user:

TimestampFormat = [%H:%M:%S]
AppendTimestamp = false
PrependTimestamp = true

It currently supports Channel, Query, Wallops, Notice and Servernotices

Format

strftime arguments can be used for the timestamps, more details and arguments can be found at opengroup.org[1].

 %a - the locale's abbreviated weekday name. 
 %A - the locale's full weekday name. 
 %b - the locale's abbreviated month name. 
 %B - the locale's full month name. 
 %c - the locale's appropriate date and time representation. 
 %C - the century number (the year divided by 100 and truncated to an integer) as a decimal number [00-99]. 
 %d - the day of the month as a decimal number [01,31]. 
 %D - same as %m/%d/%y. 
 %e - the day of the month as a decimal number [1,31]; a single digit is preceded by a space. 
 %f - sub-second, e.g. %3f is number of milliseconds (the default), and %6f is number of microseconds. (since ZNC 1.7.0)
 %h - same as %b. 
 %H - the hour (24-hour clock) as a decimal number [00,23]. 
 %I - the hour (12-hour clock) as a decimal number [01,12]. 
 %j - the day of the year as a decimal number [001,366]. 
 %m - the month as a decimal number [01,12]. 
 %M - the minute as a decimal number [00,59]. 
 %n - a newline character. 
 %p - the locale's equivalent of either a.m. or p.m. 
 %r - the time in a.m. and p.m. notation; in the POSIX locale this is equivalent to %I:%M:%S %p. 
 %R - the time in 24 hour notation (%H:%M). 
 %S - the second as a decimal number [00,61]. 
 %t - a tab character. 
 %T - the time (%H:%M:%S). 
 %u - the weekday as a decimal number [1,7], with 1 representing Monday. 
 %U - the week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. 
 %V - the week number of the year (Monday as the first day of the week) as a decimal number [01,53]. If the week containing 1 January has four or more
      days in the new year, then it is considered week 1. Otherwise, it is the last week of the previous year, and the next week is week 1. 
 %w - the weekday as a decimal number [0,6], with 0 representing Sunday. 
 %W - the week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday
      are considered to be in week 0. 
 %x - the locale's appropriate date representation. 
 %X - the locale's appropriate time representation. 
 %y - the year without century as a decimal number [00,99]. 
 %Y - the year with century as a decimal number. 
 %Z - the timezone name or abbreviation, or by no bytes if no timezone information exists. 
 %% - %.

Scripts

KVIrc

Notice: last KVIrc from SVN supports server-time, no special script needed.

Instructions for ancient KVIrc

This script requires these settings for your user:

TimestampFormat = {%H:%M:%S}
AppendTimestamp = false
PrependTimestamp = true

and here is it:

event(OnWallops,zncid)
{
	%timefront = $str.lefttofirst($3,$char(32))
	%timeappend = $str.rightfromlast($3,$char(32))
	
	if($str.matchnocase(\{**\:**\:**\},%timefront))
	{
	%time = %timefront
	%msg = $str.rightfromfirst($3,\})
	} else {
		if($str.matchnocase(\{**\:**\:**\},%timeappend))
		{
		%time = %timeappend
		%msg = $str.lefttofirst($3,\{)
		}
	}
	
	if($str.matchnocase(\{**\:**\:**\},%time))
	{
	echo -n -i=$msgtype(Wallops) $k($option(uinttimestampforeground))%time$k WALLOPS von $0 \[$1\@$2\] $str.rightfromfirst($3,\})
	}
	halt
}

event(OnServerNotice,zncid)
{
	%chan = $window.list(channel,$ic)
	%con = $window.list(console,$ic)
	%x = 0
	while(%x < %chan[]#)
		{
		if($window.hasUserFocus(%chan[%x]))
			{
			%outchan = %con
			break;
			} else {
			%outchan = %con
			}
		if(%x < %chan[]#)
			{
			%x = $(%x + 1)
			} else {
			break;
			}
		}

	%timefront = $str.lefttofirst($1,$char(32))
	%timeappend = $str.rightfromlast($1,$char(32))
	
	if($str.matchnocase(\{**\:**\:**\},%timefront))
	{
	%time = %timefront
	%msg = $str.rightfromfirst($1,\})
	} else {
		if($str.matchnocase(\{**\:**\:**\},%timeappend))
		{
		%time = %timeappend
		%msg = $str.lefttofirst($1,\{)
		}
	}
	
	if($str.matchnocase(\{**\:**\:**\},%time))
	{
	echo -n  -w=%con -i=$msgtype(ServerNotice) $k($option(uinttimestampforeground))%time$k [$0] $str.rightfromfirst($1,\})
	halt
	}
}

event(OnQueryNotice,zncid)
{
	%chan = $window.list(channel,$ic)
	%con = $window.list(console,$ic)
	%x = 0
	while(%x < %chan[]#)
		{
		if($window.hasUserFocus(%chan[%x]))
			{
			%outchan = %chan[%x]
			break;
			} else {
			%outchan = %con
			}
		if(%x < %chan[]#)
			{
			%x = $(%x + 1)
			} else {
			break;
			}
		}
		
	%timefront = $str.lefttofirst($3,$char(32))
	%timeappend = $str.rightfromlast($3,$char(32))
	
	if($str.matchnocase(\{**\:**\:**\},%timefront))
	{
	%time = %timefront
	%msg = $str.rightfromfirst($3,\})
	} else {
		if($str.matchnocase(\{**\:**\:**\},%timeappend))
		{
		%time = %timeappend
		%msg = $str.lefttofirst($3,\{)
		}
	}
	
	if($str.matchnocase(\{**\:**\:**\},%time))
	{
	echo -n  -w=%outchan -i=$msgtype(QueryNotice) $k($option(uinttimestampforeground))%time$k *$0* $str.rightfromfirst($3,\})
	halt
	}
}

event(OnQueryMessage,zncid)
{
	%timefront = $str.lefttofirst($3,$char(32))
	%timeappend = $str.rightfromlast($3,$char(32))
	
	if($str.matchnocase(\{**\:**\:**\},%timefront))
	{
	%time = %timefront
	%msg = $str.rightfromfirst($3,\})
	} else {
		if($str.matchnocase(\{**\:**\:**\},%timeappend))
		{
		%time = %timeappend
		%msg = $str.lefttofirst($3,\{)
		}
	}
	
	if($str.matchnocase(\{**\:**\:**\},%time))
		{
		echo -n -i=$msgtype(ChannelPrivateMessage) $k($option(uinttimestampforeground))%time$k $option(stringextendedprivmsgprefix)%status$0$option(stringextendedprivmsgpostfix)%msg
		halt
		}
}

event(OnChannelMessage,zncid)
{
	if(%Win{$window} > 0)
	{
	%timefront = $str.lefttofirst($3,$char(32))
	%timeappend = $str.rightfromlast($3,$char(32))
	if(($option(boolshowchanneluserflaginprivmsgview)) && ($chan.ison($0)) && ($chan.isvoice($0)))%status = $chan.getflag($0)
	
	if($str.matchnocase(\{**\:**\:**\},%timefront))
	{
	%time = %timefront
	%msg = $str.rightfromfirst($3,\})
	} else {
		if($str.matchnocase(\{**\:**\:**\},%timeappend))
		{
		%time = %timeappend
		%msg = $str.lefttofirst($3,\{)
		}
	}
	
	if($str.matchnocase(\{**\:**\:**\},%time))
		{
               if($str.containsnocase(%msg,$me))
                         {
		          echo -n -i=$msgtype(Highlight) $k($option(uinttimestampforeground))%time$k $option(stringextendedprivmsgprefix)%status$0$option(stringextendedprivmsgpostfix) %msg
		          halt
                         }else{
                         echo -n -i=$msgtype(ChannelPrivateMessage) $k($option(uinttimestampforeground))%time$k $option(stringextendedprivmsgprefix)%status$0$option(stringextendedprivmsgpostfix) %msg
		          halt
                         }
		}
	}
	
	if($0 == "***")
		{
		
		if($3 == "Buffer Playback...")
			{
			%Win{$window} = 1
			}
		if($3 == "Playback Complete.")
			{
			%Win{$window} = 0
			}
		}
}

event(OnAction,zncid)
{
	if(%Win{$window}  > 0)
		{
		
		%timefront = $str.lefttofirst($4,$char(32))
		%timeappend = $str.rightfromlast($4,$char(32))
	
		if($str.matchnocase(\{**\:**\:**\},%timefront))
		{
		%time = %timefront
		%msg = $str.rightfromfirst($4,\})
		} else {
		if($str.matchnocase(\{**\:**\:**\},%timeappend))
		{
		%time = %timeappend
		%msg = $str.lefttofirst($4,\{)
		}
	}
		
		if($chan.ison($0))%status = $chan.getflag($0)
		if($str.matchnocase(\{**\:**\:**\},%time))
			{
			echo -n -i=$msgtype(Action) $k($option(uinttimestampforeground))%time$k $0 %msg
			halt
			}
		}
}

mIRC

Notice: mIRC supports server-time since 7.33, no special script needed.

Instructions for ancient mIRC

This script requires these settings for your user:

TimestampFormat = [%H:%M:%S]
AppendTimestamp = false
PrependTimestamp = true

Otherwise you have to adjust the regex pattern in the script that grabs the timestamp.

It handles

  • Channel messages
  • Savebuff output
  • Channel notices
  • Channel actions

Configuration (optional)

If lines are too long to fit the window width they are wrapped so that the wrapped lines will line up after the nick. To disable that behavior, set %INDENT_LINES to $false.

Nicks will be prefixed with their mode identifier (so "nick" becomes "@nick" for example). To disable this behavior, set %PREFIX_NICKS to $false.

The beginning and end of buffer playback are marked with the default line separator by default. This can be changed to NORMAL to display the usual *** Buffer Playback. and *** Playback Complete messages or to NONE to not show any status message at all.

If you run into problems like all messages being displayed twice because of other ON TEXT processing scripts, try to set %EXTERNAL_RENDERER to $false.

The script also allows the use of spaces.dll to preserve consecutive spaces. To enable it just put spaces.dll (http://www.xise.nl/mirc/) into your Application Data folder and set %USE_SPACES_DLL to $true.

Script

Information about loading mIRC scripts can be found here.

alias -l config {
  ; Mandatory settings
  var %TIMESTAMP_PATTERN = ^\[(\d\d:\d\d:\d\d)\].*$
  var %PLAYBACK_BEGIN    = Buffer Playback...
  var %PLAYBACK_END      = Playback Complete.
  var %VARIABLE_PREFIX   = gbuffer
  ; Optional settings

  ; Indent wrapped lines
  var %INDENT_LINES = $true

  ; Add the mode prefix to the nick (if possible)
  var %PREFIX_NICKS = $true

  ; Are there other ON TEXT processors in place?
  var %EXTERNAL_RENDERER = $false

  ; Possible values are NORMAL/LINESEP/NONE
  var %STATUS_DISPLAY = LINESEP

  ; Make use of space-preserving spaces.dll
  var %USE_SPACES_DLL = $true

  return $eval( $+( %, $1 ), 2 )
}

alias -l makeNick {
  var %nick = $nick( $1, $2 ).pnick
  if ( ( 0 == $len( %nick ) ) || ( $true != $config( PREFIX_NICKS ) ) ) %nick = $2
  return %nick
}

alias -l handleMessage {
  var %chan = $1
  var %nick = $2
  var %color = $3
  var %pattern = $4
  var %text = $5

  var %pnick = $makeNick( %chan, %nick )

  ; Buffered input
  if ( $true == $eval( $+( %, $config( VARIABLE_PREFIX ), ., $cid, ., %chan, ., playback ), 2 ) ) {
    noop $regex( %text, $config( TIMESTAMP_PATTERN ) ) )
    var %timestamp = $regml( 1 )

    var %params
    if ( $config( INDENT_LINES ) ) %params = $+( i, $calc( $len( %timestamp ) + $len( %pnick ) + 4 ) )
    if ( %nick != $me ) %params = $+( %params, lmr )
    if ( 0 != $len( %params ) ) %params = $+( -, %params )

    if ( %nick == $me ) {
      if ( $true == $config( USE_SPACES_DLL ) ) {
        var %result
        noop $regex( %text, ^.*? (.*)$ )
        noop $regsub( %pattern, &TEXT&, $regml( 1 ), %result )
        noop $regsub( %result , &NICK&, %pnick, %result )
        noop $dll( spaces.dll, echo, $color( own  ) %params $chan %timestamp %result )
      }
      else {
        echo $color( own ) %params $chan %timestamp $replacecs( %pattern, &NICK&, %pnick, &TEXT&, $gettok( %text, 2-, 32 ) )
      }
    } 
    else {
      if ( $true == $config( USE_SPACES_DLL ) ) {
        var %result
        noop $regex( %text, ^.*? (.*)$ )
        noop $regsub( $regml( 1 ), /\\/g, \\\\, %result )
        noop $regsub( %pattern, &TEXT&, %result, %result )
        noop $regsub( %result , &NICK&, %pnick, %result )
        noop $dll( spaces.dll, echo, $color( %color ) %params $chan %timestamp %result )
      }
      else {
        echo $color( %color ) %params $chan %timestamp $replacecs( %pattern, &NICK&, %pnick, &TEXT&, $gettok( %text, 2-, 32 ) )
      }
    }
  }

  else {
    ; Current events (optional)
    if ( $true == $config( EXTERNAL_RENDERER ) ) return $false

    if ( $true == $config( USE_SPACES_DLL ) ) {
      var %result
      noop $regsub( %pattern, &NICK&, %pnick, %result )
      noop $regsub( %text, /\\/g, \\\\, %text )
      noop $regsub( %result, &TEXT&, %text, %result )
      noop $dll( spaces.dll, echo, $color( %color ) $+( -i, $calc( $len( $timestamp ) + $len( %pnick ) + 5 ), lmrt ) $chan %result )
    }
    else {
      echo $color( %color ) $+( -i, $calc( $len( $timestamp ) + $len( %pnick ) + 4 ), lmrt ) $chan $replacecs( %pattern, &NICK&, %pnick, &TEXT&, %text )
    }
  }
  return $true
}

on ^*:text:*:#:{
  ; Handle savebuff output
  if ( $nick == *savebuff ) {
    var %nick = $gettok( $2, 1, $asc( ! ) )
    var %timestamp = $asctime( $1, $timestampfmt )
    if ( $3 == MODE )     echo $color( mode ) $chan %timestamp * %nick sets mode: $4-
    elseif ( $3 == JOIN ) echo $color( join ) $chan %timestamp * %nick ( $+ $gettok( $2, 2, $asc( ! ) ) $+ ) has joined $chan
    elseif ( $3 == QUIT ) echo $color( quit ) $chan %timestamp * %nick ( $+ $gettok( $2, 2, $asc( ! ) ) $+ ) Quit ( $+ $4- $+ )
    elseif ( $3 == PART ) echo $color( part ) $chan %timestamp * %nick ( $+ $gettok( $2, 2, $asc( ! ) ) $+ ) has left $chan
    elseif ( $3 == NICK ) echo $color( nick ) $chan %timestamp * %nick is now known as $4
    elseif ( $3 == KICK ) echo $color( kick ) $chan %timestamp * $2 was kicked by $gettok( $4, 1, $asc( ! ) ) ( $+ $5- $+ )
    else                  echo $color( erro ) $chan *** UNHANDLED LINE < $+ $1- $+ >
  }

  ; Handle playback state notifications
  elseif ( $nick == *** ) {
    if ( $1- == $config( PLAYBACK_BEGIN ) ) {
      set -e $+( %, $config( VARIABLE_PREFIX ), ., $cid, ., $chan, ., playback ) $true
    }
    elseif ( $1- == $config( PLAYBACK_END ) ) {
      unset $eval( $+( %, $config( VARIABLE_PREFIX ), ., $cid, ., $chan, ., playback ), 1 )
    }

    if ( $config( STATUS_DISPLAY ) == NORMAL ) {
      echo $color( notice ) $chan *** $1-
    }
    elseif ( $config( STATUS_DISPLAY ) == LINESEP ) {
      linesep $chan
    }
  } 

  ; Handle usual input
  else {
    var %pattern = ^:.*? :(.*)$
    noop $regex( $rawmsg, %pattern )
    if ( $false == $handleMessage( $chan, $nick, normal, <&NICK&> &TEXT&, $regml( 1 ) ) ) return
  }

  halt
}

on ^*:action:*:#:{
  ;noop $dll( spaces.dll, echo, $chan $rawmsg )
  var %pattern = ^:.*? :\x01ACTION (.*)\x01$
  noop $regex( $rawmsg, %pattern )
  if ( $true == $handleMessage( $chan, $nick, action, * &NICK& &TEXT&, $regml( 1 ) ) ) halt
}

on ^*:notice:*:#:{
  ;noop $dll( spaces.dll, echo, $chan $rawmsg )
  var %pattern = ^:.*? :(.*)$
  noop $regex( $rawmsg, %pattern )
  if ( $true == $handleMessage( $chan, $nick, notice, -&NICK&- &TEXT&, $regml( 1 ) ) ) halt
}

irssi

Notice: irssi supports server-time since 1.3, just set /set show_server_time on. For details refer to the settings documentation.

Go to https://scripts.irssi.org and install the server_time.pl script. Note that you must connect to ZNC while the script is already loaded in order for it to work (loading it after you've connected will do nothing).

WeeChat

Notice: WeeChat supports server-time since 0.4.0, no special script needed.

But if you don't want to upgrade, you can try znc-playback.py

Other clients

Check documentation for your client, maybe it supports server-time too.

Clients which don't support server-time will just show the playback like this:

[08:44:30] Goldfish [monkey@2001:db8:a22c:67f::1] joined #unicorns
[08:44:30] Channel topic: O_o
[08:44:30] Topic set by Romeo!~opossum@2001:db8:451:eea6:5574:af2e:46:fe61 on Mon Mar 24 19:31:45 2014
[08:44:30] <***> Buffer Playback...
[08:44:30] <Rusty> [24 Jan 2015, 11:09:00] ah, the subfolder
[08:44:30] <Rusty> [24 Jan 2015, 11:09:00] meh
[08:44:30] <jor> [24 Jan 2015, 11:10:07] still not found
[08:44:30] <***> Playback Complete.

In this example the following settings are used:

AppendTimestamp = false
PrependTimestamp = true
TimestampFormat = [%d %b %Y, %H:%M:%S]

It feels less integrated with client, but it's not very harmful.