ADVERTISEMENT
Responsive Ad Unit • Systems Architecture & Low-Level Engineering

Timers and Time Functions in UNIX/Linux

Time is a fundamental concept in operating systems. UNIX provides multiple APIs for obtaining the current time, measuring elapsed time, tracking CPU usage, formatting dates, and suspending execution for specified intervals.

Learning Objectives

  • Understand different types of time in UNIX.
  • Learn calendar time and process time.
  • Measure elapsed and CPU time.
  • Convert and format dates.
  • Use POSIX timer APIs.
  • Suspend program execution using sleep functions.

1. What is Time in UNIX?

UNIX represents time using standardized data types and system interfaces. Applications use time values to measure durations, schedule events, record timestamps, and synchronize operations.

Different APIs are available depending on whether an application needs calendar time, CPU time, or high-resolution timing.

2. Why is Time Important?

Many operating system services depend on accurate time measurement.

  • Scheduling tasks
  • Logging events
  • Measuring execution time
  • Timeout handling
  • Performance analysis
  • File timestamps

3. Types of Time in UNIX

Type Purpose
Calendar Time Represents a date and time.
Process Time Measures CPU time consumed by a process.
Elapsed Time Measures real-world duration between events.
High-Resolution Time Provides precise timing measurements.

4. Calendar Time

Calendar time represents the current date and time. In UNIX, calendar time is commonly stored as the number of seconds that have elapsed since the UNIX Epoch.

5. UNIX Epoch

The UNIX Epoch is the reference point used for calendar time.

January 1, 1970 00:00:00 UTC ↓ Seconds Count Upward ↓ Current Time

Many UNIX time-related functions return or manipulate values relative to this reference point.

6. Process Time

Process time measures the amount of CPU time consumed by a process while it executes. Unlike calendar time, process time does not include periods during which the process is not executing on the CPU.

7. Calendar Time vs Process Time

Calendar Time Process Time
Represents wall-clock time Represents CPU usage
Advances continuously Advances only while CPU is used
Used for timestamps Used for performance measurement

8. time_t Data Type

Most UNIX calendar-time functions use the time_t data type. It represents calendar time in a form suitable for time-related system interfaces.

time_t current_time;

9. Common Time Operations

Get Current Time ↓ Convert Time ↓ Format Time ↓ Measure Duration ↓ Display Result

10. Interview Questions

  1. What is the UNIX Epoch?
  2. What is calendar time?
  3. What is process time?
  4. What is the purpose of time_t?
  5. How does process time differ from calendar time?
  6. What types of time are commonly used in UNIX?
  7. Why is accurate time measurement important in operating systems?

11. time()

The time() function returns the current calendar time as a value of type time_t. The returned value represents the number of seconds elapsed since the UNIX Epoch.

#include <time.h> time_t time(time_t *tloc);

12. Parameters and Return Value of time()

Parameter Description
tloc Optional pointer where the current time is stored.
NULL No additional storage is requested.

On success, time() returns the current calendar time as a time_t value.

13. Example: Using time()

#include <stdio.h> #include <time.h> int main() { time_t now; now = time(NULL); printf("Seconds since Epoch: %ld\n", (long)now); return 0; }

14. ctime()

The ctime() function converts a time_t value into a human-readable character string.

#include <time.h> char *ctime(const time_t *clock);

15. Example: Using ctime()

time_t now; now = time(NULL); printf("%s", ctime(&now));
time() ↓ time_t ↓ ctime() ↓ Readable Date & Time

16. gmtime()

The gmtime() function converts a time_t value into a broken-down time represented as a struct tm, using Coordinated Universal Time (UTC).

struct tm *gmtime( const time_t *clock );

17. localtime()

The localtime() function converts a time_t value into a broken-down time represented as a struct tm, using the system's local time zone.

struct tm *localtime( const time_t *clock );
time_t ↓ localtime() ↓ Local Date ↓ Local Time

18. gmtime() vs localtime()

gmtime() localtime()
Uses UTC Uses local time zone
No time-zone adjustment Applies local time-zone rules
Suitable for UTC calculations Suitable for user-facing displays

19. asctime()

The asctime() function converts a struct tm into a human-readable character string.

char *asctime( const struct tm *tm );
struct tm ↓ asctime() ↓ Readable Date String

20. difftime()

The difftime() function computes the difference, in seconds, between two calendar time values.

double difftime( time_t end, time_t beginning );
time_t start, end; start = time(NULL); /* Program work */ end = time(NULL); printf("Elapsed: %.2f seconds\n", difftime(end, start));

21. Time Conversion Flow

Current Time ↓ time() ↓ time_t ↓ gmtime() or localtime() ↓ struct tm ↓ asctime() or strftime() ↓ Formatted Output

22. Interview Questions

  1. What does time() return?
  2. What is the purpose of ctime()?
  3. What is the difference between gmtime() and localtime()?
  4. What data type does gmtime() return?
  5. What is the purpose of asctime()?
  6. How does difftime() calculate elapsed time?
  7. When should gmtime() be preferred over localtime()?

23. struct tm

The struct tm data structure represents a calendar time broken down into individual components such as year, month, day, hour, minute, and second. Functions such as gmtime() and localtime() return a pointer to this structure.

#include <time.h> struct tm;

24. Members of struct tm

Member Description
tm_sec Seconds (0–60)
tm_min Minutes (0–59)
tm_hour Hours (0–23)
tm_mday Day of month (1–31)
tm_mon Month since January (0–11)
tm_year Years since 1900
tm_wday Day of week (0–6, Sunday = 0)
tm_yday Day of year (0–365)
tm_isdst Daylight Saving Time indicator

25. Visual Representation of struct tm

struct tm ├── tm_sec ├── tm_min ├── tm_hour ├── tm_mday ├── tm_mon ├── tm_year ├── tm_wday ├── tm_yday └── tm_isdst

26. Accessing Members of struct tm

time_t now; struct tm *info; now = time(NULL); info = localtime(&now); printf("Year : %d\n", info->tm_year + 1900); printf("Month: %d\n", info->tm_mon + 1); printf("Day : %d\n", info->tm_mday);

Notice that tm_year stores the number of years since 1900, and tm_mon stores months in the range 0–11.

27. mktime()

The mktime() function converts a local broken-down time (struct tm) into a calendar time (time_t).

#include <time.h> time_t mktime( struct tm *timeptr );

28. Example: Using mktime()

struct tm date = {0}; date.tm_year = 2026 - 1900; date.tm_mon = 6; date.tm_mday = 21; date.tm_hour = 10; date.tm_min = 30; date.tm_sec = 0; time_t t = mktime(&date); printf("%ld\n", (long)t);

The example creates a calendar time corresponding to the specified local date and time.

29. strftime()

The strftime() function formats a struct tm into a character string according to a specified format.

#include <time.h> size_t strftime( char *str, size_t maxsize, const char *format, const struct tm *timeptr );

30. Common strftime() Format Specifiers

Specifier Description
%Y Four-digit year
%m Month (01–12)
%d Day of month
%H Hour (24-hour clock)
%M Minute
%S Second
%A Full weekday name
%B Full month name

31. Example: Formatting Date and Time

char buffer[100]; time_t now; struct tm *info; now = time(NULL); info = localtime(&now); strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", info); printf("%s\n", buffer);

32. Time Formatting Flow

time() ↓ time_t ↓ localtime() ↓ struct tm ↓ strftime() ↓ Formatted String

33. Interview Questions

  1. What is the purpose of struct tm?
  2. Why is tm_year stored as years since 1900?
  3. Why does tm_mon range from 0 to 11?
  4. What does mktime() return?
  5. What is the purpose of strftime()?
  6. Name four commonly used strftime() format specifiers.
  7. What is the difference between ctime() and strftime()?

34. gettimeofday()

The gettimeofday() function retrieves the current calendar time with microsecond resolution. Historically, it has been widely used in UNIX systems for measuring elapsed wall-clock time. Modern POSIX applications often prefer clock_gettime() for new development.

#include <sys/time.h> int gettimeofday( struct timeval *tv, void *tz );

35. struct timeval

The struct timeval structure stores calendar time with microsecond precision.

struct timeval { time_t tv_sec; suseconds_t tv_usec; };
Member Description
tv_sec Seconds since the UNIX Epoch
tv_usec Microseconds (0–999999)

36. Example: Using gettimeofday()

#include <stdio.h> #include <sys/time.h> int main() { struct timeval tv; gettimeofday(&tv, NULL); printf("Seconds : %ld\n", (long)tv.tv_sec); printf("Microseconds : %ld\n", (long)tv.tv_usec); return 0; }

37. clock_gettime()

The clock_gettime() function retrieves time from a specified POSIX clock with nanosecond resolution. It is the preferred interface for precise time measurements.

#include <time.h> int clock_gettime( clockid_t clockid, struct timespec *tp );

38. struct timespec

The struct timespec structure stores time with nanosecond precision.

struct timespec { time_t tv_sec; long tv_nsec; };
Member Description
tv_sec Seconds
tv_nsec Nanoseconds (0–999999999)

39. Common POSIX Clock IDs

Clock ID Purpose
CLOCK_REALTIME Current system calendar time
CLOCK_MONOTONIC Monotonic elapsed time that is not affected by setting the system clock

40. Example: Using clock_gettime()

struct timespec ts; clock_gettime( CLOCK_MONOTONIC, &ts ); printf("%ld.%09ld\n", (long)ts.tv_sec, ts.tv_nsec);

41. High-Resolution Time Flow

Application ↓ clock_gettime() ↓ Kernel ↓ Current Clock Value ↓ struct timespec ↓ Application

42. Interview Questions

  1. What is the purpose of gettimeofday()?
  2. What information is stored in struct timeval?
  3. Why is clock_gettime() preferred for precise timing?
  4. What is the difference between struct timeval and struct timespec?
  5. When should CLOCK_MONOTONIC be used instead of CLOCK_REALTIME?
  6. What resolution does clock_gettime() provide?

43. times()

The times() function measures the CPU time consumed by the calling process and its terminated child processes. Unlike time(), which returns calendar time, times() measures processor usage.

#include <sys/times.h> clock_t times( struct tms *buf );

44. struct tms

The struct tms structure stores CPU usage information for the calling process and its terminated child processes.

struct tms { clock_t tms_utime; clock_t tms_stime; clock_t tms_cutime; clock_t tms_cstime; };

45. Members of struct tms

Member Description
tms_utime User CPU time of the calling process
tms_stime System CPU time of the calling process
tms_cutime User CPU time of terminated child processes
tms_cstime System CPU time of terminated child processes

46. CPU Time Categories

Running Process | ------------------------- | | User Mode Kernel Mode | | tms_utime tms_stime

The operating system separately tracks the amount of CPU time spent executing user code and kernel code.

47. Example: Using times()

#include <stdio.h> #include <sys/times.h> #include <unistd.h> int main() { struct tms cpu; times(&cpu); printf("User CPU Time : %ld\n", (long)cpu.tms_utime); printf("System CPU Time : %ld\n", (long)cpu.tms_stime); return 0; }

48. clock()

The clock() function returns the amount of processor time consumed by the calling program. It is commonly used for measuring program execution time.

#include <time.h> clock_t clock(void);

49. Example: Using clock()

#include <stdio.h> #include <time.h> int main() { clock_t start, end; start = clock(); /* Program work */ end = clock(); printf("CPU Time = %f seconds\n", (double)(end - start) / CLOCKS_PER_SEC); return 0; }

50. time() vs times() vs clock()

Function Measures
time() Calendar (wall-clock) time
times() Process and child CPU usage
clock() CPU time consumed by the calling program

51. CPU Time Measurement Flow

Program Starts ↓ clock() ↓ Program Executes ↓ clock() ↓ Elapsed CPU Time

52. Interview Questions

  1. What is the purpose of times()?
  2. What information is stored in struct tms?
  3. What is the difference between user CPU time and system CPU time?
  4. When should clock() be used?
  5. How does clock() differ from time()?
  6. What is measured by tms_cutime?
  7. Why does times() return information about child processes?

53. sleep()

The sleep() function suspends the execution of the calling process for a specified number of seconds. If the requested interval completes without interruption, execution resumes after the specified number of seconds.

#include <unistd.h> unsigned int sleep( unsigned int seconds );

54. Return Value of sleep()

If the requested sleep interval completes successfully, sleep() returns 0. If the process is interrupted by a signal before the interval expires, the function returns the number of whole seconds remaining.

55. Example: Using sleep()

#include <stdio.h> #include <unistd.h> int main() { printf("Sleeping...\n"); sleep(5); printf("Awake\n"); return 0; }

56. sleep() Execution Flow

Program Running ↓ sleep(5) ↓ Process Suspended ↓ 5 Seconds Expire ↓ Process Resumes ↓ Continue Execution

57. nanosleep()

The nanosleep() function suspends execution for a specified interval with nanosecond precision. It provides finer control over sleep durations than sleep().

#include <time.h> int nanosleep( const struct timespec *req, struct timespec *rem );

58. Parameters of nanosleep()

Parameter Description
req Requested sleep interval
rem Remaining time if interrupted by a signal

59. Example: Using nanosleep()

#include <stdio.h> #include <time.h> int main() { struct timespec req; req.tv_sec = 2; req.tv_nsec = 500000000; nanosleep(&req, NULL); printf("Finished\n"); return 0; }

60. sleep() vs nanosleep()

sleep() nanosleep()
Seconds only Seconds and nanoseconds
Coarse precision High precision
Simple delays Precise timing applications
Returns remaining whole seconds if interrupted Can report the remaining unslept interval through rem

61. Interrupted Sleep

A sleeping process may be awakened before the requested interval has elapsed if a signal is delivered. Applications that require the full delay should check the return value and, when appropriate, continue sleeping for the remaining interval.

sleep() ↓ Signal Arrives ↓ Sleep Interrupted ↓ Remaining Time Returned ↓ Application Decides Whether to Resume Sleeping

62. Interview Questions

  1. What is the purpose of sleep()?
  2. What does sleep() return if interrupted?
  3. How does nanosleep() differ from sleep()?
  4. What is stored in the rem parameter of nanosleep()?
  5. Why is nanosleep() preferred for high-precision delays?
  6. Can a sleeping process be interrupted by a signal?
  7. When should an application resume sleeping after interruption?

63. alarm()

The alarm() function schedules the delivery of the SIGALRM signal to the calling process after a specified number of seconds. It is commonly used to implement execution time limits and timeout mechanisms.

#include <unistd.h> unsigned int alarm( unsigned int seconds );

64. Return Value of alarm()

The alarm() function returns the number of seconds remaining from any previously scheduled alarm. If no previous alarm is pending, the function returns 0.

Only one alarm can be active for a process at any given time. Scheduling a new alarm replaces the previous one.

65. Example: Using alarm()

#include <stdio.h> #include <unistd.h> #include <signal.h> void handler(int signo) { printf("SIGALRM received\n"); } int main() { signal(SIGALRM, handler); alarm(5); pause(); return 0; }

66. alarm() Execution Flow

Application ↓ alarm(5) ↓ Kernel Starts Timer ↓ 5 Seconds Expire ↓ SIGALRM Generated ↓ Signal Handler Executes ↓ Application Continues

67. Canceling an Alarm

An active alarm can be canceled by calling alarm(0).

alarm(10); /* Work */ alarm(0);

Calling alarm(0) removes any pending alarm and prevents the associated SIGALRM signal from being generated.

68. alarm() vs sleep()

alarm() sleep()
Schedules SIGALRM Suspends execution
Does not block execution Blocks the calling thread
Used for timeouts Used for delays
Application continues until the signal is delivered Application resumes only after the sleep interval expires or is interrupted

69. Typical Uses of alarm()

  • Implementing timeout mechanisms.
  • Limiting execution time of operations.
  • Interrupting long-running system calls.
  • Periodic signal generation when combined with signal handlers.

70. alarm() Lifecycle

alarm() ↓ Kernel Timer Created ↓ Timer Counts Down ↓ Timer Expires ↓ SIGALRM Delivered ↓ Handler Executes ↓ Alarm Removed

71. Interview Questions

  1. What is the purpose of alarm()?
  2. Which signal is generated by alarm()?
  3. How many active alarms can a process have?
  4. How can an existing alarm be canceled?
  5. What does alarm() return?
  6. How does alarm() differ from sleep()?
  7. When is alarm() commonly used?

72. Interaction Between alarm() and sleep()

Both alarm() and sleep() use timer facilities provided by the operating system. Historically, the implementation of sleep() on some UNIX systems was based on SIGALRM and alarm(). Modern implementations may use different mechanisms internally.

Applications should avoid assuming that alarm() and sleep() are completely independent.

73. Choosing the Appropriate Time Function

Requirement Recommended Function
Current calendar time time()
Formatted date and time strftime()
Broken-down local time localtime()
Broken-down UTC time gmtime()
Process CPU usage times()
Program CPU time clock()
High-resolution elapsed time clock_gettime()
Simple delay sleep()
Precise delay nanosleep()
Timeout using signals alarm()

74. Best Practices

  • Choose the API based on the type of time being measured.
  • Use clock_gettime() for high-resolution measurements.
  • Use CLOCK_MONOTONIC when measuring elapsed time.
  • Use strftime() instead of manually formatting dates.
  • Check return values of all time-related functions.
  • Use nanosleep() when sub-second precision is required.
  • Use alarm() only when signal-based timeouts are appropriate.

75. Common Programming Mistakes

Mistake Possible Result
Using time() for performance benchmarking Low timing precision
Using CLOCK_REALTIME for elapsed time measurements Incorrect results if the system clock changes
Ignoring interrupted sleep operations Shorter delays than expected
Forgetting that only one alarm is active per process Previously scheduled alarm is replaced
Not checking function return values Undetected runtime errors

76. Complete UNIX Time Function Comparison

Function Primary Purpose
time() Current calendar time
ctime() Convert time_t to readable string
gmtime() Convert to UTC broken-down time
localtime() Convert to local broken-down time
asctime() Convert struct tm to readable string
mktime() Convert local struct tm to time_t
strftime() Format date and time
times() Process CPU accounting
clock() Program CPU time
gettimeofday() Calendar time with microsecond resolution
clock_gettime() High-resolution POSIX clock
sleep() Delay execution
nanosleep() High-precision delay
alarm() Generate SIGALRM after a specified interval

77. Selecting the Appropriate Time Function

Need Current Time? ↓ time() ↓ Need Formatted Date? ↓ strftime() ↓ Need CPU Usage? ↓ times() ↓ Need High Precision? ↓ clock_gettime() ↓ Need Delay? ↓ sleep() or nanosleep() ↓ Need Timeout? ↓ alarm()

78. Interview Questions

  1. Why should CLOCK_MONOTONIC be preferred when measuring elapsed time?
  2. Which function should be used for formatting dates?
  3. Why is clock_gettime() preferred over gettimeofday() for precise measurements?
  4. Can more than one alarm be active for a process?
  5. When should times() be used instead of clock()?
  6. Which API should be selected for implementing a timeout?
  7. Why is checking return values important for time-related APIs?

80. Concepts Covered

  • Time in UNIX
  • Calendar Time
  • Process Time
  • UNIX Epoch
  • time_t
  • time()
  • ctime()
  • gmtime()
  • localtime()
  • asctime()
  • difftime()
  • struct tm
  • mktime()
  • strftime()
  • gettimeofday()
  • struct timeval
  • clock_gettime()
  • struct timespec
  • CLOCK_REALTIME
  • CLOCK_MONOTONIC
  • times()
  • struct tms
  • clock()
  • sleep()
  • nanosleep()
  • alarm()

81. Key Takeaways

  • Calendar time represents real-world date and time.
  • Process time measures CPU usage rather than elapsed time.
  • time_t stores calendar time values.
  • struct tm stores broken-down calendar time.
  • strftime() provides flexible date and time formatting.
  • clock_gettime() provides high-resolution POSIX timing.
  • CLOCK_MONOTONIC is suitable for measuring elapsed intervals.
  • times() and clock() measure CPU usage.
  • sleep() and nanosleep() suspend execution.
  • alarm() schedules the delivery of SIGALRM.

82. Complete Time API Review

API Primary Purpose
time() Get current calendar time
ctime() Convert calendar time to a readable string
gmtime() Convert calendar time to UTC
localtime() Convert calendar time to local time
asctime() Convert struct tm to a readable string
mktime() Convert local broken-down time to calendar time
strftime() Format date and time
times() Measure process CPU usage
clock() Measure CPU time consumed by the program
gettimeofday() Retrieve current time with microsecond resolution
clock_gettime() Retrieve high-resolution POSIX clock values
sleep() Suspend execution for seconds
nanosleep() Suspend execution with nanosecond precision
alarm() Schedule delivery of SIGALRM

83. Advanced Interview Questions

  1. Differentiate calendar time, elapsed time, and process CPU time.
  2. Why is the UNIX Epoch used as the reference point for calendar time?
  3. Explain the purpose of time_t and struct tm.
  4. Compare gmtime(), localtime(), and mktime().
  5. How does strftime() differ from ctime()?
  6. When should CLOCK_MONOTONIC be preferred over CLOCK_REALTIME?
  7. What information is stored in struct timeval and struct timespec?
  8. Explain the difference between times() and clock().
  9. How does nanosleep() improve upon sleep()?
  10. Describe how alarm() is used to implement timeouts.
  11. Why can only one alarm be active for a process?
  12. How can interrupted sleep operations be handled correctly?
  13. Which APIs are best suited for benchmarking program execution?
  14. Why is choosing the appropriate clock source important in POSIX programming?
  15. Explain a practical scenario where multiple time-related APIs are used together.
Knowledge Check

Concept Mastery Assessment — Module 22

Verify your conceptual understanding with 12 targeted technical assessment questions. Instant feedback and explanations are provided for every choice.

Question 1 of 12
What is the primary architectural purpose of Timers, Clocks & Time Functions in POSIX in operating systems?
Explanation
Timers, Clocks & Time Functions in POSIX is designed to manage calendar time vs process time, clock_realtime, clock_monotonic, timer_create, nanosleep, and high-resolution posix timers. within the operating system architecture.
Question 2 of 12
Which system interface or data structure is centrally associated with Timers, Clocks & Time Functions in POSIX?
Explanation
Under POSIX and Linux, Timers, Clocks & Time Functions in POSIX operates through standardized system calls and kernel control structures.
Question 3 of 12
What safety or concurrency constraint must developers consider when implementing Timers, Clocks & Time Functions in POSIX?
Explanation
Proper synchronization, avoidance of race conditions, and handling reentrant execution are critical when working with Timers, Clocks & Time Functions in POSIX.
Question 4 of 12
When a system call related to Timers, Clocks & Time Functions in POSIX fails in C, how does the POSIX runtime conventionally report the failure?
Explanation
Standard POSIX system calls return -1 or NULL on error, assigning an error integer (e.g. EINVAL, EPERM, EAGAIN) to the thread-local errno variable.
Question 5 of 12
What is the primary performance tradeoff associated with Timers, Clocks & Time Functions in POSIX?
Explanation
Operations involving Timers, Clocks & Time Functions in POSIX balance performance against kernel transition, memory bandwidth, and cache locality tradeoffs.
Question 6 of 12
What security principle governs access to resources in Timers, Clocks & Time Functions in POSIX?
Explanation
The kernel validates credentials, effective permissions, and Linux capabilities before granting access to protected operations.
Question 7 of 12
How does execution of Timers, Clocks & Time Functions in POSIX transition between User Space and Kernel Space?
Explanation
User space transitions to kernel mode securely via software traps or SYSCALL instructions that switch processor rings to Ring 0.
Question 8 of 12
What happens to resources allocated by Timers, Clocks & Time Functions in POSIX when the owning process terminates?
Explanation
Process resources (open fds, memory maps) are automatically reclaimed by the kernel on termination, while kernel-persistent objects survive.
Question 9 of 12
In production Linux server environments, how is Timers, Clocks & Time Functions in POSIX optimized for high throughput?
Explanation
Linux optimizes throughput via zero-copy data paths, asynchronous kernel events, and scalable concurrency primitives.
Question 10 of 12
What standard governs the portability of Timers, Clocks & Time Functions in POSIX across Unix, Linux, and macOS platforms?
Explanation
IEEE POSIX standards define consistent APIs across Unix-like platforms ensuring portable source code execution.
Question 11 of 12
Which command-line diagnostic tool is most effective for inspecting and troubleshooting Timers, Clocks & Time Functions in POSIX at runtime?
Explanation
Utilities like strace, lsof, and the /proc filesystem provide direct visibility into kernel interactions and resource status.
Question 12 of 12
What is a critical production best practice when developing systems software involving Timers, Clocks & Time Functions in POSIX?
Explanation
Defensive programming requires explicit error checking on all system operations, proper resource cleanup, and avoiding memory corruption.
0 / 12 (0%)
Great job! Review the concepts above and proceed when ready.
ADVERTISEMENT
Responsive Ad Unit • Technical Courses & Certifications