Number of communicating stations in JTDX log files (2024/12/05)
I made a program to tabulate country names by time zone from log files spit out by JTDX and wsjtx This is not a useful software at all, but it is a study of Python (Python). Click here to download JTDX_time_Ver1.0.1.zip Download count: 15_
The program isPython(Python) programming language. I've tested the operation on a Windows 11 computer.python-3.13.0-amd64must be downloaded and installed.
External libraries must be installed after Python (Python) installation
pytzOnly the "*" must be installed.
pip install pytzcommand.
You now have all the packages you need to run this program.
Installation and Directory Preparation Please unzip the file JTDX_time_Ver1.0.0.zip after downloading
The program defaults to C:\Users\kueno\AppDataLocal\JTDX C:¥Logs The red text should be rewritten to match your environment. Please rewrite the red text to match your environment. To executerunjtdx_time.batPlease activate the
Execution screen of JTDX_time_Ver1.0.0.py
It is possible to see the trend of which countries were communicated with at different times of the day.
Start JTDX_time_Ver1.0.0.pyrunjtdx_time.batfile Please rewrite the PATH relation according to your environment.
REM This is a batch file to run the JTDX_time_Ver1.0.01.py script REM Change the Python executable path if necessary
@echo off REM Set the path to Python executable set PYTHON_EXECUTABLE=python
REM Set the path to the JTDX script set SCRIPT_PATH=C:\Users\kueno\OneDrive\Desktop\JTDXLOG\JTDX_time_Ver1.0.0.py
REM Execute the script %PYTHON_EXECUTABLE% %SCRIPT_PATH%. pause
# Version No. # JTDX_time_Ver1.0.0.py # This program displays the countries of contact by time zone from the ADIF file # adi files can be passed as arguments # You can also enter an adi file. The file will be read from the PATH specified in LOGS_DIR. # or you can enter the full path # timezone. All processes are in UTC. # Search all bands if you don't enter a band # Input can be either 15m or 21MHz. # Enter the date you want to search. If not specified, it will aggregate from all of the adi files # You can enter something like 20240601 or 202406 # # Import required modules import os import sys from datetime import datetime, timedelta import pytz
# Dictionary to convert from band MHz input to m format BAND_MHZ_TO_M = { "1.8MHz": "160m", "1.8MHz". "1.9MHz": "160m", "1.9MHz". "3.5MHz": "80m", "80m". "3.7MHz": "80m", "80m". "5MHz": "60m", "5MHz".
# Function to convert band names to 'm' format def convert_band_to_m(band):. if band.endswith("MHz"): if band.endswith("MHz") return BAND_MHZ_TO_M.get(band, None) elif band in ALLOWED_BANDS:. return band else:. print("Invalid band format.") return None
def get_file_path():. if len(sys.argv) > 1:. return os.path.join(LOGS_DIR, sys.argv[1]) else:. file_name = input(f "Specify the ADIF log file path (default in {DEFAULT_ADIF_FILE}): ").strip() file_path = file_name if file_name else DEFAULT_ADIF_FILE if os.path.exists(file_path):. return file_path else:. print(f "File not found: {file_path}") return None
# Function to select time zone def select_timezone():. while True: The try:. tz_input = input("Select timezone (Enter 'UTC', 'JST', 'PHT' or a custom UTC offset (e.g., UTC+8)): ").strip()
if not tz_input:. tz_input = "UTC"
if tz_input.upper() == "JST":. return pytz.timezone("Asia/Tokyo"), "JST". elif tz_input.upper() == "PHT":. return pytz.timezone("Asia/Manila"), "PHT" elif tz_input.upper() == "UTC":. return pytz.UTC, "UTC" elif tz_input.upper().startswith("UTC"):. try:. offset = int(tz_input[3:]) return pytz.FixedOffset(offset * 60), f "UTC{tz_input[3:]}" except ValueError:. print("Invalid UTC offset. Please enter a valid UTC offset like 'UTC+8'.") else:. print("Invalid input. Please enter one of the following: 'UTC', 'JST', 'PHT' or a valid UTC offset (e.g., 'UTC+8').") except KeyboardInterrupt:. print("\nProgram interrupted. Exiting... Exiting... \n") sys.exit(0) # Exit program normally
for line in lines:. current_record += line.strip() if line.strip() == "<EOR>": if line.strip() == "<EOR>": if line.strip() == "<EOR> qso_date = extract_field(current_record, "QSO_DATE") time_on = extract_field(current_record, "TIME_ON") band = extract_field(current_record, "BAND") qth = extract_field(current_record, "QTH") or "Unknown"
if not qso_date or not time_on or not band: current_record = "" continue
if target_date and qso_date ! = target_date: ! current_record = "" continue
if target_month and not qso_date.startswith(target_month):. current_record = "" continue
normalized_band = convert_band_to_m(band) if target_band and normalized_band ! = target_band: ! current_record = "" continue
if len(time_on) == 4: if len(time_on) time_on += "00"
def display_results(results, target_band):. if not results:. print("No data found matching the criteria.") return
total_contacts = 0 print(f"\nHourly QTH Counts for Band: {target_band}") for hour_range, qths in results.items():. total_hour_contacts = sum(qths.values()) total_contacts += total_hour_contacts print(f"{hour_range}:") print(f" Total contacts: {total_hour_contacts}") for qth, count in sorted(qths.items(), key=lambda x: x[1], reverse=True):. print(f" {count} {qth}")
print(f"\nTotal contacts for all hours: {total_contacts}")
def main():. try:. DEBUG_FLAG = False # Add debug flag file_path = get_file_path() if not file_path:. return
timezone, tz_label = select_timezone()
while True: The target_band = input("Enter the target band (e.g., 15m, 21MHz, or press Enter to skip): ").strip() if not target_band or target_band in ALLOWED_BANDS or target_band in ALLOWED_MHz:. target_band = convert_band_to_m(target_band) if target_band else None break (e.g. rip) print("Invalid band. Please choose from:\n") f"{', '.join(ALLOWED_BANDS)}\n" f"{', '.join(ALLOWED_MHz)}")
target_month = input("Enter the search month\n(YYYYY, YYYYYMMDD, YYYYY/MM, YYYY/MM/DD, etc) or press Enter to search all months: ").strip()
if target_month:. if '/' in target_month:. target_month = target_month.replace('/', '') elif len(target_month) == 6:. target_month = target_month
target_date = input("Enter the target date (YYYYMMDD) or press Enter to skip: ").strip()
# Read lines from the ADIF file with open(file_path, 'r') as file:. lines = file.readlines()
save_results = input("Would you like to save the results to a TEXT file? (y/n): ").strip().lower() if save_results == 'y':. result_file = input(f "Enter the file name (default: {DEFAULT_TEXT_FILE}): ").strip() or DEFAULT_TEXT_FILE with open(result_file, 'w') as f:. f.write(f "Hourly QTH Counts for Band: {target_band}\n") for hour_range, qths in results.items():. f.write(f"{hour_range}:\n") for qth, count in qths.items():. f.write(f" {count} {qth}\n") print(f "Results saved to {result_file}") except KeyboardInterrupt:. print("\nProgram interrupted by user. Exiting...") except Exception as e:. print(f "Error: {e}")
if __name__ == "__main__":. main()
By the way, don't tell anyone that ChatGPT helped me a lot with this too! But it took two days. When I tell ChatGPT my specifications, they write a program for me, but once I start going in the wrong direction, I'm not sure I'm going to get it right. It does not heal easily. I have pointed out the mistake many times, but it is not resolved. Then you have to show them the source before the generation. Often, we find a mistake because we have moved at this time. I ended up staying with ChatGPT until 3am on the first day.
For example, this one print("Invalid band. Please choose from:\n") f"{', '.join(ALLOWED_BANDS)}\n" f"{',''".join(ALLOWED_MHz)}")
Double quotation marks in the third line are single quotation marks The last one is wrong, even though it needs to be.