Creating our first script – unix_converter.py

Our first script will perform a common timestamp conversion that will prove useful throughout this book. Named unix_converter.py, this script converts Unix timestamps into a human readable date and time value. Unix timestamps are generally formatted as an integer representing the number of seconds since 1970-01-01 00:00:00.

On line one, we provide a brief description of our script to the users, allowing them to quickly understand the intentions and uses of the script. Following this are import statements on lines two through four. These imports likely look familiar, providing support (in order) for printing information in Python 2 and 3, interpreting timestamp data, and accessing information about the version of Python used. The sys library is then used on lines 6 through 12 to check what version of Python was used to call the script to properly handle accepting user input. Python 2 uses the raw_input function to accept data at the Terminal for the user, while Python 3 implements the input function. This if/elif/else statement is then concluded with NotImplementedError for other (future) versions of Python not specified. To make things easier, we built this conditional in a manner that you can easily plug into your code. See the following for the described code:

001 """Script to convert Unix timestamps."""
002 from __future__ import print_function
003 import datetime
004 import sys
005
006 if sys.version_info[0] == 3:
007 get_input = input
008 elif sys.version_info[0] == 2:
009 get_input = raw_input
010 else:
011 raise NotImplementedError(
012 "Unsupported version of Python used.")

After an omitted license statement (please see the source code for the MIT license information), we provide additional script information for reference by the user and to standardize our script implementation. We then move to the main() function, which prompts the user for a timestamp to convert and then prints the results of the transformed timestamp from our Unix_converter() function. To break apart line 49 a little more, let's start at the innermost component, the get_input() function call. This function is supplied with a string that will be displayed to the user in front of the buffer allowing user input. This get_input() function returns a string value of the data entered into the console by the user, although we need to convert this value into an integer. We use the int class to initialize an integer value that we then store in the unix_ts variable. 

Applying concepts
How could we redesign line 49 to better handle the user input and any exceptions that may arise when accepting this data?
Hint
It may take more than one line.
042 __authors__ = ["Chapin Bryce", "Preston Miller"]
043 __date__ = 20181027
044 __description__ = """Convert Unix formatted timestamps (seconds
045 since Epoch [1970-01-01 00:00:00]) to human readable."""
046
047
048 def main():
049 unix_ts = int(get_input('Unix timestamp to convert:\n>> '))
050 print(unix_converter(unix_ts))

On line 50 in the previous code block, we call the unix_converter() function, providing the integer input from the user. This function then, as defined on line 53 in the following code, calls the datetime module and uses the utcfromtimestamp() method to read the integer as a datetime object. We are using the utcfromtimestamp() method here instead of the similarly named fromtimestamp() method, as the utcfromtimestamp() version does not apply time zone modifications to the provided data and leaves the timestamp in the original time zone. This returned datetime object is then converted into a human-readable string using the strftime() method and the resulting string is returned to the calling function, which ultimately prints this value to the console:

053 def unix_converter(timestamp):
054 date_ts = datetime.datetime.utcfromtimestamp(timestamp)
055 return date_ts.strftime('%m/%d/%Y %I:%M:%S %p')p')

Our script is concluded with two lines of code, as shown in the following snippet, which will become very frequent in the conclusions of our scripts. The first of these lines, on line 57, is a conditional that's used to check whether the script was executed as a script instead of imported as a module. This allows us to change the functionality of our code based on how it is used. In an example, a console version of our code should, generally, accept command-line arguments while a version used as a library will not need to prompt the user for those details as the calling script may only use a subset of functions within this code. This means that line 58 is the only logic we want to execute if this code is called at the command line, which starts the main() function. If this script is imported as a module to another script, nothing will occur as we have no further logic to run on import. If it is imported, we will be able to use the functions without worrying about other calls occurring on import:

057 if __name__ == '__main__':
058 main()

We can now execute this script by calling unix_converter.py at the command line. This script ran, as shown in the following screenshot, until it required input from the user. Once the value was entered, the script continued execution and printed the converted timestamp to the console: